On the Java dynamic proxy mode

Proxy design pattern UML diagram:

clipboard1-28

Java Proxy design pattern - the static agent

This example is very simple, only one way wirteCodeinterface IDeveloper:

public interface IDeveloper {
    public void writeCode();
}
// 实现这个接口的类:
public class Developer implements IDeveloper{
    private String name;
    public Developer(String name){
        this.name = name;
    }
    @Override
    public void writeCode() {
        System.out.println("Developer " + name + " writes code");
    }
}

Test code:

public class DeveloperTest {
    public static void main(String[] args) {
        IDeveloper jerry = new Developer("Jerry");
        jerry.writeCode();
    }
}

Test output:

Developer Jerry writes code

The trouble is that now, because Jerry's leadership team as developers like Jerry did not write technical documentation, it is not satisfied. After discussion, the team reached an agreement related documentation must be provided with the code.

To document without forcing developers to write directly to the existing implementation class Developer modified, you can now use a static proxy to achieve:

// 创建一个和Developer类实现同样接口的类
public class DeveloperProxy implements IDeveloper{
    private IDeveloper developer;
    // 引用Developer类对象
    public DeveloperProxy(IDeveloper developer){
        this.developer = developer;
    }
    @Override
    public void writeCode() {
        System.out.println("Write documentation...");
        this.developer.writeCode();
    }
}

Test code:

public class DeveloperTest {
    public static void main(String[] args) {
        Developer jerry = new Developer("jerry");
        DeveloperProxy jerryproxy = new DeveloperProxy(jerry);
        jerryproxy.writeCode();
    }
}

Test output:

Write documentation...
Developer jerry writes code

The advantage of the static agent

Suppose you want to enhance, without modifying the original class of existing code to achieve stability, you can create a proxy class, and achieve the original package as a proxy of private property. Enhanced functionality in the proxy class is done, the existing code is completely transparent. Returning to the example above, the client code does not care about it to call the writeCode()method of variable points to the real developers or developer code.

clipboard1-29

advantage:

  1. Easy to implement and understand
  2. The relationship between the original implementation of its agents have been determined at compile time, no additional run-time overhead.

Static agents shortcomings

We still use this example to illustrate.
Suppose now that the issue of the missing documents still exist in the QA colleagues. If we want to solve this problem through the static agent, then the agent must introduce another class.

This is the interface testers:

public interface ITester {
    public void doTesting();
}
// ITester 接口的实现类:
public class Tester implements ITester {
    private String name;

    public Tester(String name){
        this.name = name;
    }
    @Override
    public void doTesting() {
        System.out.println("Tester " + name + " is testing code");
    }
}

Testers Agent:

public class TesterProxy implements ITester{
    private ITester tester;
    public TesterProxy(ITester tester){
        this.tester = tester;
    }
    @Override
    public void doTesting() {
        System.out.println("Tester is preparing test documentation...");
        tester.doTesting();
    }
}

Output and test code:

clipboard1-30

Tester agent from the source code, we can easily see that it is the developer having the same logic. If After a period of time, we must establish a document delivery software other colleagues in the process, we must again introduce new static proxy class time, which can lead to static proxy class become very large.

Dynamic proxies in Java - call processor

Now I through a proxy class EnginnerProxyto provide agency services to all of the specific role, rather than a dedicated static proxy class individually for each of the original implementation class.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class EnginnerProxy implements InvocationHandler
{
    Object obj;
    public Object bind(Object obj)
    {
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                .getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
        System.out.println("Enginner writes document");
        Object res = method.invoke(obj, args);
        return res;
    }
}

Main notes:

  1. Not inherited from a dedicated interface having a service interface (IDeveloper or ITester), but in this variant, from the interface inheritance techniques provided by the JDK agent InvocationHandler.
  2. To ensure that the agent can be applied to all general possible implementation class, having the generic type defined in the proxy Objectvariable.
  3. When the proxy instance method call interface, it will be InvocationHandlerdefined in the invokeintercept method, wherein the person is declared by the application developer by the enhanced logic Java Reflectioncall with the original call logic.

Here's how to use the dynamic proxy InvocationHandler design and test output:

clipboard1-31

Limit dynamic proxy class

Although this variant of the success of the static agent to avoid repeating defects, but it still has a limitation, it can not be used is not inherited from the interface implementation class, that is, the use of dynamic proxy class, the class must first implement the original or a multiple interfaces, this interface is the agent interface.

Consider the following example, the product owner does not implement any interfaces:

public class ProductOwner {
    private String name;
    public ProductOwner(String name){
        this.name = name;
    }
    public void defineBackLog(){
        System.out.println("PO: " + name + " defines Backlog.");
    }
}

The following code has no syntax errors in the IDE:

ProductOwner po = new ProductOwner("Ross");
ProductOwner poProxy = (ProductOwner) new EnginnerProxy().bind(po);
poProxy.defineBackLog();

Unfortunately Times compiled the following error:

clipboard1-32

Guess you like

Origin www.linuxidc.com/Linux/2019-06/158978.htm