Design Pattern --- Proxy Pattern

1 Definition

In the proxy mode, a proxy is created for the object you want to access, so that the access original object becomes the access proxy object. Proxy mode can provide very good access control. The most common example of an agency pattern in life is an intermediary.

2 Proxy pattern structure and implementation

The general class diagram of the proxy mode is as follows (from "Dahua Design Mode"):

  • Subject
    abstract subject role: it can be an abstract class or an interface. An abstract topic is a common business type with no special requirements.
  • RealSubject
    specific subject role: also called delegated role or proxy role , is the specific executor of business logic.
  • Proxy
    agent subject role: also known as a delegate class or a proxy class . It is responsible for the application of real roles, entrusts the method restrictions defined by all abstract theme classes to the implementation of real theme roles, and does preprocessing and post-processing work before and after the processing of specific theme roles.

A proxy class can represent multiple delegates or delegates, so which specific subject role a proxy class represents is determined by the scene class. The simplest case is a subject class and a proxy class. Usually, an interface only needs one proxy class, and the specific proxy implementation class is determined by the high-level module.

3 Advantages of proxy mode

Responsibilities are clear

The specific role is to implement specific business logic, without caring about other affairs that are not part of this responsibility, and complete a transaction through a later proxy, with clear code. In some cases, a client class does not want or cannot directly refer to a delegate object, and the proxy class object can play an intermediary role between the client class and the delegate object, characterized in that the proxy class and the delegate class implement the same interface .

High scalability

The specific subject role will change at any time, but as long as the interface is implemented and the interface remains unchanged, the proxy class can continue to be used without any modification, which conforms to the " open-closed principle ".
In addition, the proxy class is not only an intermediary between the client class and the proxy class, we can also extend the function of the proxy class by adding additional functions to the proxy class. In this way, we only need to modify the proxy class without modifying the proxy class. It also conforms to the open-closed principle .

4 Static proxy

The so-called static means that the bytecode file of the proxy class already exists before the program runs , and the relationship between the proxy class and the real subject role is determined before running. Taobao merchants sell goods, which is an agent. When users want to buy something, they can directly place an order with Taobao sellers, and then they can buy their favorite goods.

4.1 Selling goods interface Sell

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 09:58
 **/
public interface Sell {

    /**
     * 卖手套
     */
    String sellGloves();

    /**
     * 卖袜子
     */
    String sellSocks();

    /**
     * 卖鞋子
     */
    String sellShoes();
}

4.2 Source merchant YONEX

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:08
 **/
public class Yonex implements Sell {

    @Override
    public String sellGloves() {
        return "卖尤尼克斯的手套";
    }

    @Override
    public String sellSocks() {
        return "卖尤尼克斯的袜子";
    }

    @Override
    public String sellShoes() {
        return "卖尤尼克斯的鞋子";
    }
}

4.3 Taobao Proxy TaoBaoProxy

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:10
 **/
public class TaoBaoProxy implements Sell{
    private final Yonex yonex;

    private String COMMON_PEDDLE = "我是淘宝代理,";

    public TaoBaoProxy(){
        yonex = new Yonex();
    }

    @Override
    public String sellGloves() {
        return COMMON_PEDDLE + yonex.sellGloves();
    }

    @Override
    public String sellSocks() {
        return COMMON_PEDDLE + yonex.sellSocks();
    }

    @Override
    public String sellShoes() {
        return COMMON_PEDDLE + yonex.sellShoes();
    }
}

4.4 Buyer

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:24
 **/
public class Buyer {

    private TaoBaoProxy taoBao;

    public Buyer(){
        taoBao = new TaoBaoProxy();
    }

    public void buyGloves(){
        System.out.println("想要买手套");
        System.out.println(taoBao.sellGloves());
    }

    public void buySocks(){
        System.out.println("想要买袜子");
        System.out.println(taoBao.sellSocks());
    }

    public void buyShoes(){
        System.out.println("想要买鞋子");
        System.out.println(taoBao.sellShoes());
    }
}

4.5 Main function MainClass

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 09:56
 **/
public class MainClass {
    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.buyGloves();
        System.out.println("-------------------------------------");
        buyer.buySocks();
        System.out.println("-------------------------------------");
        buyer.buyShoes();
        System.out.println("-------------------------------------");
    }
}

4.6 Running Results

4.7 Summary 

The static proxy mode realizes the function extension of the target object without changing the target object. The disadvantage is that the static proxy implements all the methods of the target object. Once the target interface adds methods, the proxy object and the target object must be modified accordingly, increasing the maintenance cost.

5 Dynamic proxies

The proxy method created by the proxy class when the program is running is called a dynamic proxy. In our example of static proxy above, the proxy class (TaoBaoProxy) is defined by itself and compiled before the program runs. However, dynamic proxy, the proxy class is not defined in the Java code, but dynamically generated at runtime according to our "instructions" in the Java code. Compared with static proxies, the advantage of dynamic proxies is that the functions of proxy classes can be processed in a unified manner without modifying the methods in each proxy class.

This article introduces JDK-based dynamic proxies and CGLIB-based dynamic proxies.

5.1 JDK-based dynamic proxy

JDK dynamic proxy uses a Proxy class and an InvocationHandler interface provided in the java.lang.reflect package. Proxy is used to dynamically generate proxy classes, and InvocationHandler defines the method for implementing proxy classes.

In the code implementation, the business is the same as that of the static proxy, and now the shoes, socks and gloves of Li Ning are dynamically represented.

5.1.1 Selling interface MySell

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 09:58
 **/
public interface MySell {

    /**
     * 卖手套
     */
    String sellGloves();

    /**
     * 卖袜子
     */
    String sellSocks();

    /**
     * 卖鞋子
     */
    String sellShoes();
}

5.1.2 Li Ning

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:08
 **/
public class LiNing implements MySell {

    @Override
    public String sellGloves() {
        return "卖李宁的手套";
    }

    @Override
    public String sellSocks() {
        return "卖李宁的袜子";
    }

    @Override
    public String sellShoes() {
        return "卖李宁的鞋子";
    }
}

5.1.3 Implementing InvocationHandler

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 11:55
 **/
public class MyInvocationHandler implements InvocationHandler {

    private MySell mySell;

    public MyInvocationHandler(MySell mySell){
        this.mySell = mySell;
    }

    /**
     *执行代理方法
     *
     * @param proxy 被动态代理的对象
     * @param method 代理执行的方法
     * @param args 执行的参数
     * @return method方法执行返回的参数
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("我是JDK淘宝代理");
        return method.invoke(mySell, args);
    }
}

5.1.4 Users buy Buyer

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-08 10:24
 **/
public class Buyer {

    MySell mySell = new LiNing();

    public void buyGloves(){
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(mySell);
        MySell proxy = (MySell) Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), mySell.getClass().getInterfaces(), myInvocationHandler);
        Object result = proxy.sellGloves();
        System.out.println(result);;
    }

    public void buySocks(){
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(mySell);
        MySell proxy = (MySell) Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), mySell.getClass().getInterfaces(), myInvocationHandler);
        Object result = proxy.sellSocks();
        System.out.println(result);;
    }

    public void buyShoes(){
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(mySell);
        MySell proxy = (MySell) Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), mySell.getClass().getInterfaces(), myInvocationHandler);
        Object result = proxy.sellShoes();
        System.out.println(result);;

    }
}

5.1.5 Main program

public class MainClassJdk {
    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.buyGloves();
        System.out.println("-------------------------------------");
        buyer.buySocks();
        System.out.println("-------------------------------------");
        buyer.buyShoes();
        System.out.println("-------------------------------------");
    }
}

5.1.6 Running Results

5.2 Dynamic proxy based on CGLIB

CGLIB is a powerful, high-performance code generation package. It provides proxies for classes that don't implement interfaces, providing a nice complement to the JDK's dynamic proxies. It is usually possible to create proxies using Java's dynamic proxies, but CGLIB is a good choice when the class to be proxied does not implement an interface or for better performance.

The business requirements implemented by the code are similar to the JDK dynamic proxy, and now buy victory shoes, socks and gloves.

5.2.1 Add jar package

First, you need to add the cglib jar package and the asm jar package that cglib depends on. The jar package can be downloaded from the maven repository .

5.2.2 Shop Victor

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:37
 **/
public class Victor {
    
    public String sellGloves() {
        return "卖胜利的手套";
    }

   
    public String sellSocks() {
        return "卖胜利的袜子";
    }

   
    public String sellShoes() {
        return "卖胜利的鞋子";
    }
}

5.2.3 CGLIB interceptor MyInterceptor

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:40
 **/
public class MyInterceptor implements MethodInterceptor {

    /**
     * 拦截方法
     *
     * @param o 代理的目标对象
     * @param method 目标对象的方法
     * @param objects 参数
     * @param methodProxy CGlib方法代理对象
     * @return 代理方法返回值
     * @throws Throwable 异常
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("我是CGLIB淘宝代理");
        return methodProxy.invokeSuper(o, objects);
    }
}

 5.2.4 Buyer

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:43
 **/
public class Buyer {

    public void buyGloves(){
        Victor victor = getVictor();
        System.out.println(victor.sellGloves());
    }

    public void buySocks(){
        Victor victor = getVictor();
        System.out.println(victor.sellSocks());
    }

    public void buyShoes(){
        Victor victor = getVictor();
        System.out.println(victor.sellShoes());

    }


    private Victor getVictor(){
        Enhancer enhancer =new Enhancer();
        enhancer.setSuperclass(Victor.class);
        enhancer.setCallback(new MyInterceptor());
        return (Victor) enhancer.create();
    }
}

5.2.5 Main program

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-09 11:48
 **/
public class MainClassCglib {
    public static void main(String[] args) {
        Buyer buyer = new Buyer();
        buyer.buyGloves();
        System.out.println("-------------------------------------");
        buyer.buySocks();
        System.out.println("-------------------------------------");
        buyer.buyShoes();
        System.out.println("-------------------------------------");
    }
}

5.2.6 Execution result

6 Summary

This paper mainly introduces the proxy mode in the design pattern. Through practical examples, the code is written to realize the static proxy of Java, the dynamic proxy based on JDK and the dynamic proxy based on CGLIB. This article is an introduction article, with powerful principles and code analysis behind it. You are welcome to study and make progress together.

7 Quotes

1. "Dahua Design Patterns"

2. Detailed analysis of java dynamic proxy implementation and principle

3. Detailed explanation of java dynamic proxy

4. Design Patterns - Proxy Pattern

5. Introduction and principle of CGLIB (dynamic proxy through inheritance)

8 source code

https://github.com/airhonor/design-pattern-learning/tree/main/src/com/hz/design/pattern/proxy

Guess you like

Origin blog.csdn.net/honor_zhang/article/details/120175424