Agent mode of design mode

Posted by faizulbari on Tue, 08 Mar 2022 11:33:17 +0100

The design principle is a summary of some experience guiding our code design, that is, "mental method"; Object oriented is our "weapon"; Design pattern is "move".

Based on mental skill, use weapon moves to deal with complex programming problems.

Me: sister, what do I think you've been busy lately? Didn't you change to a lighter job?

Cousin: Yes, it's easier to work, but it's too far to go to and from work. I want to buy a used car for transportation, so I'm doing my homework now.

Me: let me see Wow, quite serious. Did it take a lot of time?

Cousin: Yes, I didn't know much about this before, so now I have to do my homework before I dare to buy it.

Me: one of my classmates is an agent in this field. I asked him to help you.

Cousin: Wow, that will save me a lot of trouble~

You see, this is the [agent mode] in our design mode?

Why use proxy mode?

  • Intermediary isolation

    In some cases, a client class does not want or cannot directly reference a delegate object, and the proxy class object can play an intermediary role between the client class and the delegate object. Its characteristic is that the proxy class and the delegate class implement the same interface.

  • Add functions without violating the opening and closing principle

    In addition to being the intermediary between the client class and the delegate class, the proxy class can also add additional functions to expand the function of the delegate class. In this way, we only need to modify the proxy class without modifying the delegate class, which is in line with the opening and closing principle of code design. The agent class is mainly responsible for preprocessing messages for the delegate class, filtering messages, forwarding messages to the delegate class, and processing the returned results afterwards.

    The proxy class does not really implement services, but provides specific services by calling the relevant methods of the delegate class. The real business function is still realized by the delegate class, but some public relations services can be added before and after the implementation of the business function. For example, by adding functions such as caching and logging, we can use the proxy class instead of modifying the encapsulated delegate class.

According to the creation date of agents, they can be divided into static agents and dynamic agents.

Static agent: it is created by programmers or automatically generated by specific tools, and then compiled. Before compiling and running, the proxy class The class file has been created, and the relationship between the proxy class and the delegate class is determined before running.

Dynamic agent: the source code of dynamic agent class is dynamically generated by JVM according to reflection and other mechanisms during program operation, so there is no bytecode file of agent class. The relationship between proxy class and delegate class is determined when the program runs.

How is the static proxy implemented?

The premise of proxy implementation is how to get the call of delegate class? The answer is that there are two ways: combination and inheritance.

Composition: implement the same interface as the delegate class, and then pass the reference of the delegate class to the proxy class to call the target function.

Inheritance: inherit the delegate class, rewrite the target function, and then call the target function through super.

Let's take a look at the implementation in combination. Take the example of my cousin buying a used car.

Step 1: create a car buying interface:

1 public interface IBuyCar {
2     void buyCar() 
3 }

Step 2: cousin wants to buy a car and realize the interface of buying a car

1 public class BiaoMeiBuyCar implements IBuyCar {
2     @Override 
3     public void buyCar() {
4         System.out.println("Trading used cars");
5     }
6 }

Step 3: find an agent to help your cousin finish it

 1 public class BiaoMeiBuyCarProxy implements IBuyCar {
 2     private IBuyCar buyCar;
 3     
 4     public BiaoMeiBuyCarProxy (final IBuyCar buyCar) {
 5         this.buyCar = buyCar;
 6     }
 7     
 8     @Override
 9     public void buyCar() {
10         // In addition to helping with the transaction, the agent also helps with the pre and post formalities
11         System.out.println("Pre transaction procedures");   
12         buyCar.buyCar();  // transaction
13         System.out.println("Post transaction procedures");
14     }
15 }
1 IBuyCar buyCar = new BiaoMeiBuyCarProxy (new BiaoMeiBuyCar());

Because the delegate class and proxy class implement the same interface and are based on the interface rather than programming, replacing the BiaoMeiBuyCar class object with the BiaoMeiBuyCarProxy class object does not need to change too much code.

Have you found that the static proxy mode based on combination is very similar to the decorator mode.

Yes, for the decorator mode, both the decorator and the decorated implement an interface; For proxy mode, both proxy class and delegate class implement the same interface. No matter which mode we use, we can easily add custom methods before or after the methods of real objects.

Here, let's take a brief look at the differences between the two. In another article, we will carefully analyze the differences between the two design patterns.

Agent mode focuses on the process control and assistance of a certain function of the object. It can control the object to do something. The focus is to borrow the function of the object to complete a certain process, rather than how the function of the object is.

The decorator mode focuses on the expansion of the object function, does not care about how the outside world calls, and only focuses on strengthening the object function. After decoration, it is still the object itself.

However, if the delegate class does not define an interface and the delegate class code is not developed and maintained by us (for example, it comes from a third-party Class Library), we can't directly modify the original class and redefine an interface. In this case, how can we implement the static proxy mode?

In this case, we generally adopt the method of inheritance. Let the proxy class inherit the delegate class, and then extend the additional functions.

 1 public class BiaoMeiBuyCar {
 2     public void buyCar() {
 3         System.out.println("Trading used cars");
 4     }
 5 }
 6  7 public class BiaoMeiBuyCarProxy extends BiaoMeiBuyCar {
 8     public void buyCar() {
 9         // In addition to helping with the transaction, the agent also handled the pre and post formalities for his cousin
10         System.out.println("Pre transaction procedures");
11         super.buyCar();   // transaction
12         System.out.println("Post transaction procedures");
13     }
14 }
15 16 public class Demo {
17     public static void main(String[] args) {
18         // 1,Proxy object not found
19         BiaoMeiBuyCar biaomeiBuyCarProxy = new BiaoMeiBuyCarProxy();
20         // 2,The agent is responsible for helping his cousin take care of everything
21         biaomeiBuyCarProxy .buyCar();
22     }
23 }

You see, whether the static proxy mode is based on combination or inheritance, on the one hand, all the methods in the original class need to be re implemented in the proxy class, and similar code logic needs to be attached to each method. On the other hand, if there is more than one class to add additional functions, we need to create a proxy class for each class. That will inevitably increase the number of classes and increase the cost of code maintenance. Moreover, the code in each proxy class is a bit like template "repeated" code, which also increases the unnecessary development cost.

At this time, dynamic agents come in handy.

Dynamic agent

In the dynamic agent, we no longer need to create the agent class manually, but only need to write a dynamic processor.

JDK dynamic agent

The real proxy object is dynamically created by JDK at runtime.

Step 1: create a car buying interface:

1 public interface IBuyCar {
2     void buyCar() 
3 }

Step 2: cousin wants to buy a car and realize the interface of buying a car

1 public class BiaoMeiBuyCar implements IBuyCar {
2     @Override 
3     public void buyCar() {
4         System.out.println("Trading used cars");
5     }
6 }

Step 3: implement dynamic processor

 1   import java.lang.reflect.InvocationHandler;
 2   import java.lang.reflect.Method;
 3  4   public class DynamicProxyHandler implements InvocationHandler {
 5       private Object object;
 6       
 7       public DynamicProxyHandler(final Object object) {
 8           this.object = object;
 9       }
10      
11      @Override 
12      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
13          System.out.println("Pre transaction procedures");
14          Object result = method.invoke(object, args);
15          System.out.println("Post transaction procedures");
16          return result;
17      }
18  }
1 public class Demo {
2      public static void main(String[] args) {
3          IBuyCar biaomeiBuyCar = new BiaoMeiBuyCar();
4          IBuyCar buyCarProxy = (IBuyCar)Proxy.newProxyInstance(IBuyCar.class.getClassLoader(), new Class[]{IBuyCar.class}, new DynamicProxyHandler(biaomeiBuyCar));
5          buyCarProxy.buyCar();
6      }
7  }

However, JDK needs to implement classes to define business methods through interfaces to implement dynamic proxy. For classes without interfaces, CGLib is required.

CGLIB dynamic proxy

CGLib adopts very low-level bytecode technology. Its principle is to create a subclass for a class through bytecode technology, and use method interception technology in the subclass to intercept the calls of all parent methods and weave cross cutting logic.

However, because inheritance is adopted, the class modified by fianl cannot be proxied.

Step 1: create CGLib proxy class.

 1 package wei.proxy.impl;
 2  3 import net.sf.cglib.proxy.Enhancer;
 4 import net.sf.cglib.proxy.MethodInterceptor;
 5 import net.sf.cglib.proxy.MethodProxy;
 6  7 import java.lang.reflect.Method;
 8  9 public class CglibProxy implements MethodInterceptor {
10     private Object target;
11     public Object getInstance(final Object target) {
12         this.target = target;
13         Enhancer enhancer = new Enhancer();
14         enhancer.setSuperclass(this.target.getClass());
15         enhancer.setCallback(this);
16         return enhancer.create();
17     }
18 19     public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
20         System.out.println("Pre transaction procedures");
21         Object result = methodProxy.invokeSuper(object, args);
22         System.out.println("Post transaction procedures");
23         return result;
24     }
25 }
1 public class Demo {
2     public static void main(String[] args){
3         IBuyCar biaomeiBuyCar = new BiaoMeiBuyCar();
4         CglibProxy cglibProxy = new CglibProxy();
5         BiaoMeiBuyCar buyCarCglibProxy = (BiaoMeiBuyCar) cglibProxy.getInstance(biaomeiBuyCar);
6         buyCarCglibProxy.buyCar();
7     }
8 }

Advantages of agent mode

1. Proxy mode can isolate the proxy object from the real called target object;

2. The coupling degree of the system is reduced to a certain extent, and the expansibility is good;

3. It can protect the target object;

4. It can enhance the function of the target object;

Disadvantages of agent mode

1. Agent mode will increase the number of classes in system design;

2. Adding a proxy object between the client and the target object will slow down the request processing speed;

3. It increases the complexity of the system.

Application scenario of agent mode

Agent mode is often used to develop some non functional requirements in business systems, such as monitoring, statistics, authentication, current limiting, transaction, idempotent and log.

We decouple these additional functions from business functions and put them into the agent class for unified processing, so that programmers only need to focus on business development.

In addition to RPC caching, proxy caching, etc,

summary

In fact, the proxy mode is to introduce a certain degree of indirection when accessing objects, because this indirection can be added for a variety of purposes.

The agent is the representative of the real object.

reference material

https://www.cnblogs.com/yanggb/p/10952843.html

Geek time column "the beauty of design patterns"

https://www.cnblogs.com/daniels/p/8242592.html

Topics: Java Design Pattern