Design Patterns--Agent Patterns

Keywords: Java JDK Attribute

1. What is the agency model?

Agent pattern is one of the most common design patterns. When the target class is inconvenient to operate, another class is used instead of the target class to perform the same operation.
Intention: Provide a proxy for other objects to control access to this object.

II. Static Agent and Dynamic Agent
Static proxy: The proxy class is written by the programmer. The program has been compiled before it runs, instead of being generated dynamically in the process of running the program. This is called static.
There are two ways to change existing code. 1) Modify the original code directly, but this does not conform to the principle of open extension and close modification.
2) Adding proxy class can be realized by static proxy.
3) For example, to print time-consuming logs before and after the original method, we can use proxy classes to achieve this function. The target class and the proxy class implement the same interface. In the proxy class, the object of the target class is regarded as an attribute, and then the original method is called. Modified code can also be added.

//Interface
public interface Image {
    
    void display();    
}

//proxy class
public class ProxyImage implements Image {

    private RealImage realImage;//Objects of the target class
    
    public ProxyImage(RealImage realImage) {
        this.realImage = realImage;
    }
    
    @Override
    public void display() {
        
        long startTime = System.currentTimeMillis();
        realImage.display();
        long endTime = System.currentTimeMillis();
        System.out.println("implement display Method time-consuming:"+(endTime-startTime));
    }
}

//Target class
public class RealImage implements Image {

    @Override
    public void display() {
        System.out.println("Start displaying pictures");        
    }
}
//Testing does not change the original logic, but adds new functions.
public class Test {

    public static void main(String[] args) {
        RealImage realImage = new RealImage();
        ProxyImage proxyImage = new ProxyImage(realImage);
        proxyImage.display();
    }
}

Dynamic proxy: The proxy class is created during the running of the program. The advantage of dynamic agent is that it is very convenient to handle the functions of agent class uniformly. Instead of modifying each method in the proxy class. It is divided into JDK dynamic agent and CGlib dynamic agent.
1) JDK dynamic proxy: also known as interface-based proxy
java.lang.reflect.Proxy: Generate dynamic proxy classes and objects;
java.lang.reflect.InvocationHandler processor interface;
(1) Define a processor class, implement the invocationHandler interface, and rewrite the invoke method.
(2) The proxy class implements the same interface as the target class
(3) Call Proxy.newProxyInstance(...) to generate a proxy instance.
(4) Calling methods through proxy instances

//Interface
public interface Subject {
    
    int sellBooks();        
}
//Target class
public class RealSubject implements Subject {
    @Override
    public int sellBooks() {
        System.out.println("Selling books");        
        return 1;
    }    
}
//Custom processor, each proxy class object corresponds to a processor
public class MyInvocationHandler implements InvocationHandler {

    Subject realSubject;
    
    public MyInvocationHandler(Subject realSubject) {
        this.realSubject = realSubject;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Call proxy class");        
        int count = (int)method.invoke(realSubject, args);//Methods to execute target classes
        System.out.println("It's the method of selling books.");
        return count;
    }
}
//
public class Test{
    
    public static void main(String[] args) {
        Subject realSubject = new RealSubject();        
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
        Class cls = realSubject.getClass();
        
        Subject proxyClass = (Subject)Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), myInvocationHandler);
        proxyClass.sellBooks();        
    }    
}

In the test class, the proxy class object is acquired through the static method of Proxy class. There are three parameters, one is the class loader (target class), the interface implemented by the proxy class, and the processor object. The proxy class is generated dynamically during the running process of the program, and then the proxy object is generated. The static thing is that we've written it before it runs.

2) CGlib dynamic proxy: Generate a subclass dynamically for the proxy class, and then the subclass overrides the methods in the proxy class. If it is a private or final modifier, it will not be rewritten.
CGlib is a powerful, high-performance code generation package. It provides proxy for classes without interfaces, and provides a good complement for JDK dynamic proxy.

public class Engineer {

    //Can be proxy
    public void eat() {
        System.out.println("The engineer is eating.");
    }
    
    //Cannot be overridden by generated subclasses
    public final void work() {
        System.out.println("The engineer is working.");
    }
    
    //Cannot be overridden by generated subclasses
    private void play() {
        System.out.println("the engineer is playing game");
    }
}

public class CglibProxy implements MethodInterceptor {

    private Object target;
    
    public CglibProxy(Object target) {
        this.target = target;
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib Dynamic proxy invoked");
        Object result = method.invoke(target, objects);        
        return result;
    }
    
    public static Object getProxy(Object target) {
        Enhancer enhancer = new Enhancer();
        //Setting up objects that need proxy
        enhancer.setSuperclass(target.getClass());
        //Setting agent
        enhancer.setCallback(new CglibProxy(target));
        return enhancer.create();
    }
}

public class TestCglib {
    
    public static void main(String[] args) {
        
        //Generating proxy classes
         Engineer proxyEngineer = (Engineer)CglibProxy.getProxy(new Engineer());
         proxyEngineer.eat();
    }
}

As can be seen from the examples above, we can implement cglib dynamic proxy. You need to implement an interface (a processor like a jdk dynamic proxy) and then override the methods in it, then set up the target class and the proxy class.

Posted by thetechgeek on Tue, 24 Sep 2019 20:13:44 -0700