Patrón de diseño --- Patrón de proxy

1 Definición

En el modo proxy, se crea un proxy para el objeto al que desea acceder, de modo que el objeto original de acceso se convierte en el objeto proxy de acceso. El modo proxy puede proporcionar un muy buen control de acceso. El ejemplo más común de un patrón de agencia en la vida es un intermediario.

2 Estructura e implementación del patrón proxy

El diagrama de clase general del modo proxy es el siguiente (del "Modo de diseño de Dahua"):

  • Sujeto
    Rol de sujeto abstracto: puede ser una clase abstracta o una interfaz. Un tema abstracto es un tipo de negocio común sin requisitos especiales.
  • Rol de sujeto específico de RealSubject
    : también llamado rol delegado o rol de proxy , es el ejecutor específico de la lógica de negocios.

  • Rol de sujeto del agente proxy : también conocido como clase de delegado o clase proxy . Es responsable de la aplicación de roles reales, confía las restricciones de método definidas por todas las clases de temas abstractos a la implementación de roles de temas reales y realiza trabajos de preprocesamiento y posprocesamiento antes y después del procesamiento de roles de temas específicos.

Una clase de proxy puede representar a varios delegados o delegados, por lo que la clase de escena determina qué rol de sujeto específico representa una clase de proxy. El caso más simple es una clase sujeto y una clase proxy. Por lo general, una interfaz solo necesita una clase de proxy y la clase de implementación de proxy específica está determinada por el módulo de alto nivel.

3 ventajas del modo proxy

Las responsabilidades son claras.

El rol específico es implementar una lógica de negocios específica, sin importar otros asuntos que no sean parte de esta responsabilidad, y completar una transacción a través de un proxy posterior, con código claro. En algunos casos, una clase de cliente no quiere o no puede referirse directamente a un objeto delegado, y el objeto de clase delegado puede desempeñar un papel de intermediario entre la clase de cliente y el objeto delegado, caracterizado porque la clase delegado y la clase delegado implementan el misma interfaz .

Alta escalabilidad

El rol de sujeto específico cambiará en cualquier momento, pero mientras se implemente la interfaz y la interfaz permanezca sin cambios, la clase de proxy puede continuar usándose sin ninguna modificación, lo que se ajusta al " principio abierto-cerrado ".
Además, la clase de proxy no solo es un intermediario entre la clase de cliente y la clase de proxy, también podemos extender la función de la clase de proxy agregando funciones adicionales a la clase de proxy. De esta manera, solo necesitamos modificar el proxy clase sin modificar la clase proxy. También se ajusta al principio abierto-cerrado .

4 Proxy estático

El llamado estático significa que el archivo de código de bytes de la clase de proxy ya existe antes de que se ejecute el programa , y ​​la relación entre la clase de proxy y el rol de sujeto real se determina antes de ejecutar. Los comerciantes de Taobao venden productos, que es un agente. Cuando los usuarios quieren comprar algo, pueden realizar un pedido directamente con los vendedores de Taobao y luego pueden comprar sus productos favoritos.

4.1 Interfaz de venta de bienes Vender

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

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

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

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

4.2 Comerciante fuente 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 Proxy de Taobao Proxy de TaoBao

/**
 * @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 Comprador

/**
 * @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 Función principal 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 Resultados de ejecución

4.7 Resumen 

El modo de proxy estático realiza la extensión de la función del objeto de destino sin cambiar el objeto de destino. La desventaja es que el proxy estático implementa todos los métodos del objeto de destino. Una vez que la interfaz de destino agrega métodos, el objeto proxy y el objeto de destino deben modificarse en consecuencia, lo que aumenta el costo de mantenimiento.

5 proxies dinámicos

El método de proxy creado por la clase de proxy cuando el programa se está ejecutando se denomina proxy dinámico. En nuestro ejemplo de proxy estático anterior, la clase de proxy (TaoBaoProxy) se define por sí misma y se compila antes de que se ejecute el programa. Sin embargo, proxy dinámico, la clase de proxy no está definida en el código Java, sino que se genera dinámicamente en tiempo de ejecución de acuerdo con nuestras "instrucciones" en el código Java. En comparación con los proxies estáticos, la ventaja de los proxies dinámicos es que las funciones de las clases de proxy se pueden procesar de manera unificada sin modificar los métodos en cada clase de proxy.

Este artículo presenta proxies dinámicos basados ​​en JDK y proxies dinámicos basados ​​en CGLIB.

5.1 Proxy dinámico basado en JDK

El proxy dinámico de JDK usa una clase de proxy y una interfaz InvocationHandler proporcionada en el paquete java.lang.reflect. El proxy se usa para generar dinámicamente clases de proxy, e InvocationHandler define el método para implementar clases de proxy.

En la implementación del código, el negocio es el mismo que el del proxy estático, y ahora los zapatos, calcetines y guantes de Li Ning se representan dinámicamente.

5.1.1 Interfaz de venta 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 Implementación del controlador de invocación

/**
 * @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 Usuarios compran Comprador

/**
 * @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 Programa principal

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 Resultados de ejecución

5.2 Proxy dinámico basado en CGLIB

CGLIB es un potente paquete de generación de código de alto rendimiento. Proporciona servidores proxy para clases que no implementan interfaces, lo que proporciona un buen complemento para los servidores proxy dinámicos de JDK. Por lo general, es posible crear proxies utilizando proxies dinámicos de Java, pero CGLIB es una buena opción cuando la clase que se va a utilizar no implementa una interfaz o para un mejor rendimiento.

Los requisitos comerciales implementados por el código son similares a los del proxy dinámico JDK, y ahora compre zapatos, calcetines y guantes de victoria.

5.2.1 Agregar paquete jar

Primero, debe agregar el paquete jar cglib y el paquete jar asm del que depende cglib.El paquete jar se puede descargar desde el repositorio de maven .

5.2.2 Tienda Víctor

/**
 * @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 Interceptor CGLIB 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 Comprador

/**
 * @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 Programa principal

/**
 * @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 Resultado de la ejecución

6 Resumen

Este artículo introduce principalmente el modo proxy en el patrón de diseño. A través de ejemplos prácticos, se escribe el código para realizar el proxy estático de Java, el proxy dinámico basado en JDK y el proxy dinámico basado en CGLIB. Este artículo es un artículo de introducción, con principios poderosos y análisis de código detrás de él. Le invitamos a estudiar y progresar juntos.

7 citas

1. "Patrones de diseño Dahua"

2. Análisis detallado de la implementación y el principio del proxy dinámico de Java

3. Explicación detallada del proxy dinámico de Java

4. Patrones de diseño - Patrón proxy

5. Introducción y principio de CGLIB (proxy dinámico por herencia)

8 código fuente

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

Supongo que te gusta

Origin blog.csdn.net/honor_zhang/article/details/120175424
Recomendado
Clasificación