interface-related design patterns (2): Proxy mode, identity type mode, and constant interface mode

Source: Internet
Author: User

In the above interface-related design pattern (1), detailed description of the custom service mode and adapter mode, the following we look at the third interface-related mode: proxy mode.

Proxy Mode

Definition: provides a proxy for an object to control access to the object.

Classification:

    1. Remote Proxy-Provides a local area network representative object for different geographic objects. (Similar to client and server side)
    2. Virtual Proxy-The object that consumes a lot of resources as needed is deferred and created when it is really needed. (The loading of the picture in the Web page, first with a virtual image to display, and so on after the picture is loaded and then displayed)
    3. Protection agent (Protect Proxy)-controls the user's access rights. (Post function)
    4. Smart Reference Agent (Smart Reference Proxy)-provides some additional services to target objects. (Station agency for railway station)

The following is an example of smart reference proxy, which describes two implementations of proxies: static agents and dynamic proxies.

    • static proxies : Proxies and proxied objects are determined before the agent, both implementing the same interface or inheriting the same abstract class.

The following is a simple example that shows a car object being timed by the agent:

package com.proxy;publicinterface Moveable {//汽车的行驶功能    void move();}

If there is no proxy, the timing function of the car will be realized when the car is driving itself:

 PackageCom.proxy;ImportJava.util.Random; Public  class Car implements moveable{    @Override     Public void Move() {LongStartTime = System.currenttimemillis (); System.out.println ("The car starts running");Try{Thread.Sleep (NewRandom (). Nextint ( +)); System.out.println ("in-drive"); }Catch(Interruptedexception e)        {E.printstacktrace (); }LongEndTime = System.currenttimemillis (); System.out.println ("The end of the car, travel time is:"+ (Endtime-starttime) +"MS"); }}

For this scenario, we can create a proxy to specifically implement the timing function, as follows:

package  Com.proxy;public  class  carproxy1  extends  car  {   @Override  public  void  move  () {long  Starttim        E = System.currenttimemillis ();        System.out.println ( "car start drive" );        super . Move ();        long  endTime = System.currenttimemillis (); System.out.println ( "car end, driving time:"  + (Endtime-starttime) +     "MS" ); }}

In this case, the Move method in the car class can only travel, the timing function to the agent to implement, car class in the Move method code is as follows:

publicvoidmove() {        try{            Thread.sleep(new Random().nextInt(1000));            System.out.println("行驶中");        }catch(InterruptedException e){            e.printStackTrace();        }    }

Now we need to access the car without having to instantiate the car class directly, but by accessing its proxy: CarProxy1 instance, as follows:

package com.proxy;publicclass Test {    publicstaticvoidmain(String []args){       CarProxy1 car  new CarProxy1();       car.move();    }}

The above is implemented by means of inheritance, and can also be implemented in a combination way, that is, not by inheriting the car class, but by wrapping the car class to call the car instance's driving function. The code is as follows:

 PackageCom.proxy; Public  class CarProxy2 implements moveable{    PrivateCar car; Public CarProxy2(Car car) {Super(); This. car = car; }@Override     Public void Move() {LongStartTime = System.currenttimemillis (); System.out.println ("The car starts running"); Car.move ();LongEndTime = System.currenttimemillis (); System.out.println ("The end of the car, travel time is:"+ (Endtime-starttime) +"MS"); }}

A proxy class that is created by composition requires that the car object be instantiated before the proxy is instantiated, with the following code:

package com.proxy;publicclass Test {    publicstaticvoidmain(String []args){        new Car();        CarProxy2 carProxy2  new CarProxy2(car);        carProxy2.move();    }}

Similar to the adapter mode of the class in adapter mode, the adapter mode of the object, the combination of proxy mode is more flexible than the way of inheritance, it is recommended to use the combination method. For example, the car to achieve logging and other functions, the use of inheritance to create a new agent to inherit CarProxy1, and then add the function will be unlimited down inheritance, difficult to maintain.

Dynamic Agent

In the example above, we have created a time record agent for the car, so what if we have to record the time for the train and the plane? It is necessary to create proxy classes for trains and airplanes separately. We need a way to take the recording time of this agent out, so when the need for different modes of transport to achieve the recording time function, the direct use of the extraction of the agent, this can greatly reduce the code reuse rate. This leads to the dynamic agent.

Dynamic agent is the dynamic generation of agents, the implementation of different classes, different methods of the agent. Here's a look at the JDK Dynamic Agent . The following is the implementation mechanism of the JDK dynamic agent:

, the dynamic agent of the JDK is actually adding a Proxyhandler class between the proxy class Proxysubject and the proxy class Realsubject, the Proxyhandler class implements the Invocationhandler interface. It acts as a transaction processor, such as the log processing for the car's timing, and the processing of the time is done in this Proxyhandler class.
Invocationhandler Interface source code is as follows:

package java.lang.reflect;publicinterface InvocationHandler {    publicinvoke(Object proxy, Method method, Object[] args)        throws Throwable;}

The first parameter proxy represents the proxy object, the second parameter means the method being proxied, and the third parameter represents the parameter array of the method.

JDK Dynamic Agent Implementation steps:

    1. To create a class that implements Invocationhandler, you must implement the Invoke method
    2. Creating a proxied class and interface
    3. Call the static method of proxy and create a proxy class
    4. Calling methods by proxy

1, to create a class that implements Invocationhandler, you must implement the Invoke method:

 PackageCom.jdkproxy;ImportJava.lang.reflect.InvocationHandler;ImportJava.lang.reflect.Method; Public  class Timehandler implements Invocationhandler {    PrivateObject object; Public Timehandler(Object object) {Super();//The object being proxied         This. Object = object; }/** * Proxy: Agent Object * Method: Methods of proxy Object * Args: Method parameter * Return: Call method's return value */    @Override     PublicObjectInvoke(Object Proxy, Method method, object[] args)throwsThrowable {LongStartTime = System.currenttimemillis (); System.out.println ("The car starts running"); Method.invoke (object);LongEndTime = System.currenttimemillis (); System.out.println ("The end of the car, travel time is:"+ (Endtime-starttime) +"MS");return NULL; }}

Step 2,3,4, the following is the test class:

 PackageCom.jdkproxy;ImportJava.lang.reflect.InvocationHandler;ImportJava.lang.reflect.Proxy;ImportCom.proxy.Car;Importcom.proxy.Moveable; Public  class Test {     Public Static void Main(String[]args) {Car car =NewCar (); Invocationhandler h =NewTimehandler (car); Class<?> cls = Car.getclass ();/** * Loader: Class loader * Interfaces: Implemented interface * H Invocationhandler */Moveable M = (moveable) proxy.newproxyinstance (Cls.getclassloader (), Cls.getinterfaces (), h);    M.move (); }}

Operation Result:

Cglib Dynamic Agent:
The Cglib proxy implementation principle is similar to the JDK dynamic proxy, except that the proxy object it generates during runtime is a subclass of the target class extension. Cglib is an efficient code generation package that relies on ASM (open source Java bytecode editing class library) to operate bytecode implementations that are more robust than JDK. Mainly used to retrofit legacy systems, which typically do not inherit specific interfaces.

Cglib dynamic Proxy implementation needs to import the relevant package, imported here as Cglib-nodep-2.1_3.jar, then need to create a transaction processor class, and implement Methodinterceptor interface, transaction processor class Cglibproxy source code as follows:

 PackageCom.cjlibproxy;ImportJava.lang.reflect.Method;ImportNet.sf.cglib.proxy.Enhancer;ImportNet.sf.cglib.proxy.MethodInterceptor;ImportNet.sf.cglib.proxy.MethodProxy; Public  class cglibproxy implements methodinterceptor {    PrivateEnhancer enhancer =NewEnhancer (); PublicObjectGetProxy(Class clazz) {//Set class to create subclassesEnhancer.setsuperclass (Clazz); Enhancer.setcallback ( This);returnEnhancer.create (); }/** * Interception of calls to all target class methods * instance of the Obj target class * Reflection object of the target method * parameter of the args method * instance of proxy class */    @Override     PublicObjectIntercept(Object obj, Method m, object[] args, Methodproxy proxy)throwsThrowable {//Agent's business logicSystem.out.println ("Agent: Drive");//proxy class calling methods of the parent classProxy.invokesuper (obj, args);//Agent's business logicSystem.out.println ("Agent: Arrived");return NULL; }}

There is a train class that does not implement the interface:

package com.cjlibproxy;publicclass Train {    publicvoidmove(){        System.out.println("火车行驶中...");    }}

Test class:

package com.cjlibproxy;publicclass Test {    publicstaticvoidmain(String[]args){        new CglibProxy();        Train t = (Train) proxy.getProxy(Train.class);        t.move();    }}

Test results:

Summary: The use of the JDK dynamic agent and Cglib Dynamic agent is very simple, if you can understand the internal implementation process to more profound understanding of dynamic agents, the simulation of the JDK dynamic agent implementation will be added later in the article.

Identity Type mode

Defines an interface that does not contain any methods, and uses it only to represent an abstract type. All classes that implement the interface imply that this type belongs.

For example, define a food interface, which does not contain any methods:

publicinterface Food{}//实现该接口的类都是食物类型

Fish:

publicclass Fish implements Food{...}

How to Eat:

public void eat(Food food){...}

Eating:

new Fish();//Fish实现了Food接口,标识其食物类型eat(fish);//合法new Book();//Book未实现Food接口eat(book);//编译错误

The so-called identity type pattern is a semantic constraint on the food parameters passed to the Eat () method with the help of the Java compiler. The food interface is known as the identity type interface, which has no methods and represents only an abstract type. In the JDK, there are two typical representations of type interfaces.

    • Java.io.Serializable interface: An instance of a class that implements the interface can be serialized
    • Java.io.Remote interface: An instance of a class that implements the interface can be used as a remote object
constant Interface Mode

Some constants are used in a software system, and a popular practice is to define the relevant constants in a dedicated constant interface, for example:

package com.FinalInterface;publicinterface MyConstants {    publicstaticfinaldouble3.1415926;    publicstaticfinaldouble2.71828;}

The following circle classes require access to the above Math_pi constants in one way, using direct access, as follows:

package com.FinalInterface;publicclass Circle {    privatedouble r;//半径    publicCircle(double r){        this.r = r;    }    publicdoublegetCircumference(){        return2 * r * MyConstants.MATH_PI;    }}

The import static statement was introduced in JDK1.5, which allows class A to directly access static constants in another interface B or Class B without specifying the name of interface B or Class B, and Class A does not need to implement Interface B or inherit Class B. As follows:

package  com. Finalinterface; import  static  com. finalinterface.myconstants.*; public     class  circle  { private  double  R;    //radius  public  circle  (double  R)    {this . R = r; } public  double   Getcircumference  () {return  2  * r * math_p    I; }}

The import static statement simplifies programming and prevents the circle class from inheriting and exposing static constants in Myconstants.

Combined with my previous article: interface-related design patterns (1): Customized service mode and adapter mode in detail, a total of 5 design patterns related to the interface are recorded, namely the custom service mode, adapter mode, proxy mode, identity type mode and constant interface mode. Interface is an important magic weapon to build loosely-coupled software systems. The advantage of an interface is that a class can implement multiple interfaces, and the advantage of an interface is that it is not allowed to provide implementation at the expense of any method (JAVA8 default method is not considered).

We can use the interface as the highest level abstract type in the system. From the perspective of the external user (another system), the interface promises to the user what services the system can provide, and at the point of view of the system itself, the interface specifies which services the system must implement. Interfaces are used to interact between systems, which can improve loose coupling between systems.

As for abstract classes, it is used to customize the extensibility points in the system. Abstract classes can be thought of as intermediate between "abstraction" and "implementation". The abstract class accomplishes part of the implementation in its own way, but there are some functions that need to be implemented by its subclasses.

interface-related design patterns (2): Proxy mode, identity type mode, and constant interface mode

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.