Translation Tipatterns - Object decoupling

zhaozj2021-02-16  156

Object decoupling

The proxy mode and status (State) mode provide a proxy class (Surrogate Class) for you to use; the class that is active is hidden by the proxy class. When you call a method of a proxy class, the proxy class is just a way to call the Implementing Class. These two modes are very similar, in fact, the proxy mode is only a special case of the State mode.

Some people tried to collect these two modes together to Surrogate mode, but "proxy", this term has been used for a long time, and it has its own special meaning, and these meaning is basically embodied. The difference in mode mode.

The basic concepts of these two modes are very simple: surrogate and implementation classes are derived from the same base class:

When you create a proxy object (Surrogate Object), an implementation (object) is created, and the proxy object will pass all method calls to implement the object.

From the structure, the difference between the agent (PROXY) mode and the state mode is very simple: one agent (proxy) only corresponds to an implementation, but a state (state) can correspond to multiple implementations. "Design Mode" One believes that the application of these two models is completely different: proxy mode for controlling access to implementation (class), and status mode can dynamically change the implementation ( class). However, if "Controls Access to Implementation" is expanded, these two modes can be combined with elegance.

Agent: Tap everything for another object (Proxy: fronting for another object)

Let's implement the agent (Proxy) mode according to the illustration above, below is implementing code:

//: Proxy: proxyDemo.java

// Simple Demonstration of the Proxy Pattern.

Package proxy;

Import junit.framework. *;

Interface proxybase {

Void f ();

Void g ();

Void h ();

}

Class Proxy IMPLEments Proxybase {

Private proxybase us

Public proxy () {

Implementation = new importation ();

}

// Pass method calls to the importation:

Public void f () {typementation.f ();

Public void g () {emplementation.g ();

Public void h () {typementation.h ();

}

Class Implementation Implements Proxybase {

Public void f () {

System.out.println ("IMplementation.f ()");

}

Public void g () {

System.out.println ("Implementation.g ()");}

Public void h () {

System.out.println ("Implementation.h ()");

}

}

Public class proxydemo extends testcase {

Proxy P = New Proxy ();

Public void test () {

// this Just Makes Sure IT Will Complete

// WITHOUT THROWING AN Exception.

P.f ();

P.g ();

p.h ();

}

Public static void main (string args []) {

Junit.textui.teStrunner.run (ProxyDemo.class);

}

} ///: ~

Of course, it is not to say that the implementation class and agent classes must implement exactly the same interface; since the agent class only represents the class that requires it to submit (the REFERRING) method, this has met the basic requirements of the Proxy mode (note here The definitions given by GOF books are different. Despite this, it is still very convenient to define a public interface, so that all methods required to be called (Proxy) needed to implement the implementation of the Implementation Realization.

Implement PoolManager with Proxy mode

//: Proxy: poolmanager.java

Package proxy;

Import java.util. *;

Public class poolmanager {

Private static class poolitem {

Boolean Inuse = FALSE;

Object Item;

POOLITEM (Object item) {this.Item = item;}

}

Public class releasablereference {// used to build the proxy

PRIVATE POOLITEM REFERENCE;

Private boolean reclass = false;

Public releaseablereference (poolitem reason) {

THIS.REFERENCE = REFERENCE;

}

Public Object getReference () {

IF (released)

Throw new runtimeException

"Tried to Use Reference After It Was Released");

Return Reference.Item;

}

Public void release () {

Released = true;

Reference.INUSE = FALSE;

}

}

Private arraylist items = new arraylist ();

Public Void Add (Object Item) {

Items.Add (New poolitem (item));

}

// Different (better?) Approach to Running Out of items:

Public Static Class EmptyPoolItem {}

Public relevasablereference get () {

For (INT i = 0; I

PoolItem Pitem = (poolitem) items.get (i); if (pitem.inuse == false) {

Pitem.INUSE = True;

Return New RelevasableReference (Pitem);

}

}

// Fail as soon as you try to cast it:

// Return New EmptyPoolItem ();

Return null; // Temporary

}

} ///: ~

//: Proxy: ConnectionPoolProxyDemo.java

Package proxy;

Import junit.framework. *;

Interface connect {

Object get ();

Void Set (Object X);

Void release ();

}

Class Connection IMPLEments Connection {

Public Object Get () {Return Null;}

Public void set (Object s) {}

Public void release () {} // never caled directly

}

Class connectionPool {// a singleton

Private static poolmanager pool = new poolmanager ();

Private connectionPool () {} // prevent synthesized constructor

Public Static Void AddConnections (int Number) {

For (int i = 0; i

Pool.Add (New ConnectionImplementation ());

}

Public static connection getConnection () {

PoolManager.releasableReference RR =

PoolManager.releasablereference) pool.get ();

IF (rr == null) Return NULL;

Return New ConnectionProxy (RR);

}

// The Proxy as a nested class:

Private stat

Class ConnectionProxy IMPLEments Connection {

Private poolManager.releaseablereference.

public

ConnectionProxy (PoolManager.releasableReference RR) {

Implementation = rr;

}

Public Object get () {

Return

(()). Get ()). Get ();

}

Public void set (Object X) {

((Connection) Implementation.getReference ()). Set (x);

}

Public void release () {typementation.release ();

}

}

Public class connectionPoolProxyDemo Extends Testcase {

STATIC {

ConnectionPool.AddConnections (5);

}

Public void test () {

Connection C = ConnectionPool.getConnection (); C.SET (New Object ());

C.Get ();

C.RELEASE ();

}

Public void testdisable () {

Connection C = ConnectionPool.getConnection ();

String s = null;

C.SET (New Object ());

C.Get ();

C.RELEASE ();

Try {

C.Get ();

} catch (exception e) {

s = E.getMessage ();

System.out.println (s);

}

Assertequals (s,

"Tried to Use Reference After It Was Released");

}

Public static void main (string args []) {

Junit.textui.teStrunner.run

ConnectionPoolProxyDemo.class;

}

} ///: ~

Dynamic Proxies

JDK1.3 introduces dynamic proxy. Although it is a bit complex, it is indeed an attractive tool. This interesting small example proves this, when the Invocation Handler is called, the proxy mechanism starts working. This is an example of very cool, it is in my mind, but I have to come up with some reasonable things to INVOCATION HANDLER, so that I can mention a useful example ... (the author has not been written)

// Proxy: DynamicProxyDemo.java

// Broken in JDK 1.4.1_01

Package proxy;

Import java.lang.reflect. *;

INTERFACE FOO {

Void f (string s);

Void G (INT I);

String H (INT I, STRING S);

}

Public class dynamicproxydemo {

Public static void main (string [] CLARGS) {

Foo Prox = (foo) proxy.newproxyinstance

Foo.class.getclassLoader (),

NEW class [] {foo.class},

New invocationhandler () {

Public Object Invoke

Object Proxy, Method Method,

Object [] args) {

System.out.println (

InvocationHandler Called: "

"/ n / tmethod =" method);

IF (args! = null) {

System.out.println ("/ targs =");

For (int i = 0; i

System.out.println ("/ t / t" args [i]);

}

Return NULL;

}

});

Prox.f ("Hello");

Prox.g (47);

Prox.h (47, "hello");

}

} ///: ~

Exercise: Create an object as a front end of a simple profile with a dynamic agent of Java as a simple profile. For example, there is an entry in a good_stuff.txt file: a = 1

B = 2

C = "Hello World"

Client programmers can use (you wrote) NeatPropertyBundle Class:

NEATPROPERTYBUNDLE P =

New NeatPropertyBundle ("Good_stuff");

System.out.println (P.A);

System.out.println (p.b);

System.out.println (p.c);

The configuration file can contain any internal, arbitrary variable names. Dynamic agent either returns the value of the corresponding attribute or tells you that it does not exist (possibly by returning null). If you shake an original value, the dynamic agent creates a new entry. Tostring ()

The method should display all current entries.

Exercise: Similar to the previous practice, connect a DOS's autoexec.bat file with a dynamic agent of Java.

Exercise: Accept a SQL query statement that can return data and then read the metadata of the database. Provide an object for each record (Record), with the property: column names and the corresponding data type (Data types).

Exercise: Write a simple server and client with XML-RPC. Each client returned to the object of the dynamic proxy concept to implement the remote method of the execable. (翻, don't know what it means)

Reader Andrea wrote:

In addition to the last exercise, I think that the above practice you give it is not. I am more willing to regard the Invocation Handler as a (Orthogonal) stuff with the proxy object.

In other words, the implementation of the Invocation Handler should be completely unrelated to those interfaces provided by the dynamically created agent object. That is to say, once the Invocation Handler is written, you can use it for any exposure interface, or even those that are late and interfaces that appear later than Invocation Handler.

That is why I want to say that the service provided by Invocation Handler is the OrthogNAL orthogonal. Rickard gave several Handler in his SmartWorld example, where I like that call - retry (Call-retry) handler. It first calls the actual object (the agent) actual object, if the call generates an exception or waiting timeout, try three times. If these three times failed, then returned an exception. This handler can be used for any class.

The Handler's implementation is too complicated relative to what you talk about here, I just want to explain what I mean is the orthogonal service.

The few exercises you given, in my opinion, the only thing that is suitable for using the dynamic proxy is the last practice that uses XML-RPC communicating with objects. Because the mechanism you use to distribute messages (referring to XML-RPC) is completely orthogonal to that object you want to create communication.

Status mode: Change the behavior of the object (state: Changing Object Behavior)

A (state) object used to change the class.

Signs: Almost all methods appear (the same) condition (expression) code. In order to make the same method call to produce a different behavior, the State mode switches its corresponding implementation within the lifecycle of the agent. This is a method for optimizing the code when you find that you must make a lot of tests before you decide how to implement any one. For example, a fairy tale frog prince contains an object (a biological), which depends on the state itself. You can use a boolean value to represent its state, the test program is as follows:

//: State: KissingPrincess.java

Package stat;

Import junit.framework. *;

Class Creature {

Private boolean isfrog = true;

Public void greet () {

IF (isfrog)

System.out.Println ("Ribbet!");

Else

System.out.println ("DARLING!");

}

Public void kiss () {isfrog = false;

}

Public class kissingprincess exceeds testcase {

Creature Creature = New Creature ();

Public void test () {

Creature.greet ();

Creature.kiss ();

Creature.greet ();

}

Public static void main (string args []) {

JUnit.textui.teestrunner.run (kissingprindess.class);

}

} ///: ~

However, the GREET () method (and all other methods that must be tested before the completion of the ISFROG value) will eventually generate a large pile of difficulty code. If these operations are delegated to a state object, the code will be simple.

//: State: kissingprincess2.java

Package stat;

Import junit.framework. *;

Class Creature {

Private interface state {

String response ();

}

PRIVATE CLOG IMPLEMENTS State {

Public string response () {return "ribbet!";

}

Private class prince imports state {

Public string response () {return "DARLING!";

}

Private state stat = new frog ();

Public void greet () {

System.out.println (State.Response ());

}

Public void kiss () {state = new prince ();

}

Public class kissingprincess2 extends testcase {

Creature Creature = New Creature ();

Public void test () {

Creature.greet ();

Creature.kiss (); creature.greet ();

}

Public static void main (string args []) {

Junit.textui.teStrunner.run (kissingprindesses2.class);

}

} ///: ~

In addition, the state of state is automatically passed to all where it is used, without the need to manually edit the class to make the change take effect.

The following code demonstrates the basic structure of the State mode.

//: State: StateDemo.java

// Simple Demonstration of The State Pattern.

Package stat;

Import junit.framework. *;

Interface statE {

Void Operation1 ();

Void Operation2 ();

Void Operation3 ();

}

Class serviceProvider {

PRIVATE STATE;

Public serviceProvider (state state) {

THIS.STATE = State;

}

Public Void ChangeState (State newState) {

State = newstate;

}

// Pass method calls to the importation:

Public void service1 () {

// ...

State.Operation1 ();

// ...

State.operation3 ();

}

Public void service2 () {

// ...

State.Operation1 ();

// ...

State.operation2 ();

}

Public void service3 () {

// ...

State.operation3 ();

// ...

State.operation2 ();

}

}

Class Implementation1 IMPLEments State {

Public void Operation1 () {

System.out.println ("Implementation1.Operation1 ()");

}

Public void Operation2 () {

System.out.println ("Implementation1.Operation2 ()");

}

Public void Operation3 () {

System.out.println ("Implementation1.Operation3 ()");

}

}

Class Implementation2 IMPLEments State {

Public void Operation1 () {

System.out.println ("Implementation2.Operation1 ()");

}

Public void Operation2 () {

System.out.println ("Implementation2.Operation2 ()");

}

Public void Operation3 () {

System.out.println ("Implementation2.Operation3 ()");

}

}

Public class statEMo Extends testcase {

Static void Run (ServiceProvider SP) {

Sp.service1 ();

Sp.service2 ();

Sp.Service3 ();

}

ServiceProvider SP = New ServiceProvider (New Implementation1 ());

Public void test () {

Run (sp);

Sp.changestate (New Implementation2 ());

Run (sp);

}

Public static void main (string args []) {

Junit.textui.teStrunner.Run (StateDemo.class);

}

} ///: ~

In the main () function, first use the first implementation, then transfer to the second implementation.

When you implement the State mode, you will encounter a lot of details. You must choose the right implementation method according to your needs, such as whether the status used (State) is to expose to the customer, and how to make the status Variety. Some cases (such as Swing LayoutManager, the client can pass object directly, but in the KissingPrincess2.java, the status is invisible for the client. In addition, the mechanism for changing the state may be simple or complicated -, such as the state machine to mention later, there will be a series of status and different mechanisms of changing the state.

The example mentioned above this is very interesting, which reflects the behavior of Strategy mode and State mode.

The difference between Proxy mode and State mode is different from what they solve. In "design mode" is the general application describing the Proxy mode:

1. Remote Proxy provides a local agent for an object in different address spaces. A Remote Proxy Is Created for You Automatically by The Rmi Compiler RMIC AS It Creates Stubs and

2. Virtual Proxy, use "Lazy Initialization" when creating complex objects as needed.

3. Protection Proxy is used for you to do not want the client-side service to fully control the proxiet object.

4. Smart Reference. When accessing the subject object, additional actions are provided. For example, it can be used to count the references for specific objects, thereby implementing COPY-ON-WRITE, thereby avoiding object alias (Object aliasing). A simpler example is the number of times used to record a particular approach.

You can regard the reference in Java as a protection agent that controls access to the actual object assigned to the heap (and you can guarantee a null reference) .

[Override: In the "Design Mode" book, Proxy mode and State mode are considered to be unlessed, because the structure given by the book is completely different (I think this The implementation is a bit arbitrary). Especially in the State mode, it uses a separate implementation hierarchy, but I don't have to do it, unless you identify that the code is not controlled by you (of course, this is also a possible situation, but if the code is by you To control, then more simple and practical use of a separate base class). In addition, the implementation of the Proxy mode does not need to use a public base class because the agent object only controls access to the subject object. Despite the differences in detail, the Proxy mode and State mode are transmitted to implement the object with a proxy (Surrogate) to implement the object. The State mode is visible everywhere, because it is the most basic idea, for example, in the Builder mode, "Director" is a backend's buider object to generate different behaviors.

Iterator: Isolation Algorithm and Container (Iterators: Decoupling Algorithms from Containers)

Alexander Stepanov (with Dave Musser) Write STL before you have used the issue of generic programming. Finally, he concluded that all algorithms are defined above the Algebraic Structures - we call the algebraic structure as a container.

In this process, he realizes that I iterator is critical to the application of algorithms because it is isolated from the algorithm from the particular type of container it. This means that when the algorithm is described, it is not necessary to consider the particular sequence it operate. More general, any code written by using iterator is separated from the data structure it operate, so that these code is more common and is easy to reuse.

Another application area of ​​the iterator is Functional programming. Its goal is to describe every step of the program, not what is done by the description program. That is to say, use "sort" (order), not the algorithm for the sorting. The purpose of C STL is to provide support for this generic programming method for C languages ​​(this method is successfully requested to be verified).

If you have used Java's container classes (write code does not have to be very difficult), then you must use iterators -java1.0 / 1.1 put it as an enumerator (enumeration), Java2.0 is called iteration Matter - You are definitely familiar with their general usage. If you are still unfamiliar, you can refer to Thinking In Java Second Edition Chapter 9 (you can download from www.bruceeckel.com).

Because Java2 containers are very dependent on iterators, they become the best candidate technology for generic programming / functional programming. This chapter explains these technologies by transplanting STL to Java, (transplanted iterators) will be used with Java2's container classes.

Type-Safe Iterators

In the second edition of Thinking in Java, I implemented a type of secure container class that only accepts a particular type of object. Reader Linda Pazzaglia wants me to implement another type of secure component, a container-compatible iterator that can be defined in java.util, but to limit the object it has traversed must be the same type. If the Java has a template mechanism, the above (Type Security) iterator can easily return a particular type of object. However, there is no template mechanism, you must return Generic Objects, or manually add code for each object that needs to be traversed. Here I will use the previous method.

Another problem that needs to be decided in design (Design Decision) When is the type of object. One method is the type of the first object traversed by iterators (as the type of iterator), but this method will have problems when the container class is re-sorted according to its own internal algorithm (such as a Hash table). So two traversal of the same iterator may get different results. The security practice is to let the user specify the type of iterator when constructing an iterator.

The final problem is how to build an iterator. We can't rewrite existing Java class libraries, which already contains an enumerator and iterator. However, we can use the Decorator mode to create an extension of an enumerator or iterator, generate a new one with the iterative behavior we want (this example, refers to the incorrect type when it is incorrect. Object, and this new object has the same interface with the original enumerator or iterator, so that it can be used in the same occasion (maybe you will argue, this is actually Proxy mode, but from its purpose (Intent) is more like Decorator mode).

The implementation code is as follows:

//: COM: Bruceeckel: util: typediterator.java

Package com.bruceeckel.util;

Import java.util. *;

Public class type {{

PRIVATE ITERATOR IMP;

Private class type;

Public TypedITERATOR (Iterator IT, Class Type) {

IMP = IT;

THIS.TYPE = TYPE;

}

Public Boolean Hasnext () {

Return Imp.hasNext ();

}

Public void remove () {imp.remove ();

Public Object next () {

Object obj = Imp.next ();

IF (! type.isinstance (obj))

Throw new classcastexception

"Typediterator for type" Type

"Encountered Type:" Obj.getClass ());

Return Obj;

}

} ///: ~

Exercise:

1. Write a "Virtual Proxy".

2. Write a "SmartReference" agent, use this agent to record the number of methods called a particular object.

3. In anticipated a DBMS system, write a program to limit the maximum number of connections. Control the number of connection objects with methods similar to Singleton. When the user releases a connection, it is necessary to notify the system to collect the released connection to reuse. In order to ensure this, write a proxy object instead of a reference to the connection, further design this proxy to allow the connection to release the system. 4. With State mode, write a UnpredictablePerson class, which changes the response to the Hello () method according to your own emotion (MOOD). Write an additional Mood class: Prozac.

5. Write a simple Copy-ON Write implementation.

6.java.util.map does not provide a method of reading the "Key-Value" pair from a two-dimensional array. Write an Adapter class to implement this feature.

7. Create an adapter factory tria Dynamically Finds and products the adapter That You NEED TO Connect A Given Object to a designired interface.

8. Use the dynamic agent of the Java Standard Library to redo practice 7.

9. Rewrive this section of the Object Pool so that the object is automatically recovered from the object pool for another time.

10. Remote Exercise 9, use "Leasing" method such that the client can refresh the "rental object" to prevent automatic release of the target timing.

11. Consider thread factors and rewrite Object Pool.

table of Contents

转载请注明原文地址:https://www.9cbs.com/read-8701.html

New Post(0)