Clasificación de 12 patrones de diseño comunes y escenarios de aplicación en Java

Tabla de contenido

patrón único

modo hombre hambriento

modo perezoso

modo de bloqueo de hilo

Modo de doble juicio

patrón de clase interno estático

patrón de estrategia

patrón de fábrica

fábrica sencilla

fábrica abstracta

modo fachada

patrón decorador

modelo de cadena de responsabilidad

modo de peso mosca

Patrón de observador

modo proxy

modo proxy estático

Modo proxy dinámico

patrón de adaptador

patrón de prototipo

patrón de método de plantilla


patrón único

        El modo Singleton es un modo de diseño anticuado en Java. Creo que todo el mundo ha entrado en contacto con él en el trabajo. En lo que a mí respecta, los principales escenarios de aplicación del modo Singleton son los siguientes:

        Es adecuado para escenarios donde los objetos se obtienen con frecuencia en el proyecto, tales como: obtener objetos de caché, obtener algunos objetos de herramientas, etc., porque estos objetos se usan con frecuencia, por lo que al obtener objetos, usamos el modo singleton para especificar para obtener un objeto.

El siguiente editor lo llevará a revisar nuevamente el método de escritura del modo singleton Aquí presentaremos los cinco métodos de escritura del modo singleton .

modo hombre hambriento

 La estructura del código es la siguiente:

  1. objeto final estático privado directo nuevo
  2. constructor privado sin argumentos
  3. método de instancia pública estática

        El modo de hombre hambriento es uno de los métodos de escritura comúnmente utilizados en el modo singleton. La característica principal es crear directamente un objeto al definir un objeto. El código detallado es el siguiente:

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 单例模式 饿汉式
 *  上来就new对象
 **/
public class SignletonHungry {

    //1. 私有的静态的最终的对象
    private static final SignletonHungry singl=new SignletonHungry();

    //2. 私有的无参构造函数
    private SignletonHungry(){

    }

    //3. 公共的静态的实例方法
    public static SignletonHungry getInstance(){
        return singl;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonHungry.getInstance().hashCode());
            }).start();
        }
    }
}

        Debajo de la clase, definimos un método de prueba para simular y verificar si el método hashcode del objeto obtenido a través de la clase singleton es consistente cada vez durante el acceso concurrente de subprocesos múltiples. Si es consistente, significa seguridad de subprocesos. Los resultados de la ejecución son como sigue:

Se puede ver que los resultados de ejecución son consistentes.Este tipo de método de escritura chino hambriento generalmente se usa más en proyectos reales.

Ventajas: Esta forma de escribir es relativamente simple, es decir, la instanciación se completa cuando se carga la clase, lo que evita el problema de la sincronización de hilos.

Desventajas: Pero debido a que el objeto se inicializa cuando se especifica el objeto, cuando la clase es relativamente grande, también causará una cierta cantidad de consumo de recursos.

modo perezoso

La estructura del código es la siguiente:

  1. Los objetos estáticos privados están vacíos y no son nuevos.
  2. constructor privado sin argumentos
  3. método de instancia pública estática

        Para evitar las deficiencias mencionadas anteriormente del estilo del hombre hambriento, se amplía el método de escritura singleton del estilo del hombre perezoso. Al definir el objeto, la inicialización no se realiza directamente. En el método de creación de instancias real, se realiza la operación de inicialización, que guarda Ciertos recursos, el código de implementación específico es el siguiente:

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *
 * 单例模式 懒汉式
 * 调用实例方法时才new对象
 * 节省空间 缺点是线程不安全
 **/
public class SignletonFull {

    //1. 私有的静态的对象 先不new 默认为null值
    private static SignletonFull signletonFull;

    //2. 私有的无参构造器
    private SignletonFull(){}

    //3. 公共的静态的方法
    public static SignletonFull getInstance() throws InterruptedException {
        if(signletonFull==null){
            Thread.sleep(1000);
            signletonFull=new SignletonFull();
        }
        return signletonFull;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                try {
                    System.out.println("获取的hashCode是: "+SignletonFull.getInstance().hashCode());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

        De manera similar, bajo esta clase, también definimos un método de prueba para simular y verificar si el método hashcode del objeto obtenido a través de la clase singleton es consistente cada vez durante el acceso concurrente de subprocesos múltiples.Si es consistente, significa seguridad de subprocesos. resultados de la siguiente manera:

        Podemos ver que el modo de hombre perezoso tiene problemas de seguridad en el sitio cuando la adquisición simultánea de subprocesos múltiples de clases singleton, por lo tanto, dado que existen problemas de seguridad de subprocesos, ¿cómo podemos mejorar este problema? Consulte Modo de bloqueo de hilo.

modo de bloqueo de hilo

 La estructura del código es la siguiente:

  1. Los objetos estáticos privados están vacíos y no son nuevos.
  2. constructor privado sin argumentos
  3. Método de instancia estática compartida, agregue modificación de sincronización al juzgar si el objeto está vacío

        Los bloqueos de subprocesos se pueden utilizar para resolver los problemas de seguridad de subprocesos en el modo Lazy Man. El código de implementación específico es el siguiente:

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *
 * 单例模式之 加锁
 * 线程安全 缺点是效率低 受synchronized锁升级的影响
 **/
public class SignletonThread {
    //1. 私有的静态的对象
    private static SignletonThread signletonThread;

    //2. 私有的构造方法
    private SignletonThread(){}

    //3. 公共的静态的实例方法 在if里面加上锁synchronized
    public static SignletonThread getInstance(){
        if (signletonThread==null){
            synchronized (SignletonThread.class){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                signletonThread=new SignletonThread();
            }
        }
        return signletonThread;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonThread.getInstance().hashCode());
            }).start();
        }
    }
}

        De manera similar, bajo esta clase, también definimos un método de prueba para simular y verificar si el método hashcode del objeto obtenido a través de la clase singleton es consistente cada vez durante el acceso concurrente de subprocesos múltiples.Si es consistente, significa seguridad de subprocesos. resultados de la siguiente manera: 

         Podemos ver que el resultado de la ejecución no es satisfactorio. ¿Por qué? Esto se debe a que cuando el código sincronizado se ejecuta rápido, algunos hilos ya han obtenido el objeto, lo que lleva a la inconsistencia de los objetos obtenidos. Entonces, ¿cómo resolver este problema?

Modo de doble juicio

La estructura del código es la siguiente:

  1. Los objetos estáticos privados están vacíos y no son nuevos.
  2. constructor privado sin argumentos
  3. Método de instancia estática compartida, agregue modificación de sincronización al juzgar si el objeto está vacío
  4. En el juicio, juzga si está vacío otra vez
package designmodel.signelton;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *
 * 单例写法
 * 双重判断式
 **/
public class SignletonThreadTwo {

    //1. 私有的静态的对象
    private static SignletonThreadTwo signletonThreadTwo;

    //2. 私有的构造方法
    private SignletonThreadTwo(){}

    //3. 公共的静态的实例方法 在if里面加上锁synchronized 在锁块中继续判断是否为空
    public static SignletonThreadTwo getInstance(){
        if (signletonThreadTwo==null){
            synchronized (SignletonThreadTwo.class){
                if(signletonThreadTwo==null){
                    signletonThreadTwo=new SignletonThreadTwo();
                }
            }
        }
        return signletonThreadTwo;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonThreadTwo.getInstance().hashCode());
            }).start();
        }
    }
}

        De manera similar, bajo esta clase, también definimos un método de prueba para simular y verificar si el método hashcode del objeto obtenido a través de la clase singleton es consistente cada vez durante el acceso concurrente de subprocesos múltiples.Si es consistente, significa seguridad de subprocesos. resultados de la siguiente manera:  

        Veamos los resultados de la ejecución. Aunque los resultados de la ejecución son los que queremos, debido a la introducción de bloques de código sincronizados, también se introducen los conceptos de bloqueos ligeros y bloqueos pesados. Aunque la seguridad de los subprocesos está garantizada, se pierden las bonificaciones de rendimiento. Y eso es fácil causar interbloqueo, entonces, ¿hay alguna forma de ser seguro y eficiente para subprocesos? 

patrón de clase interno estático

La estructura del código es la siguiente:

  1. constructor privado sin argumentos
  2. clase interna estática privada
  3. Defina un objeto estático final privado en la clase interna, uno nuevo
  4. Defina un método de instancia pública que devuelva una clase interna.
package designmodel.signelton;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 单例模式
 * 通过静态内部类实现懒加载与线程安全
 * 利用JVN特性实现 JVM在加载类和内部类的时候 只会在运行的时候加载一次 从而保证线程安全和懒加载
 **/
public class SignletonStaticClass {

    //1. 私有的无参构造器
    private SignletonStaticClass(){}

    //2. 私有的静态的内部类
    private static class SignletonStatic{
        //3. 在私有的内部类中定义私有的 最终的 静态的对象
        private final static SignletonStaticClass signletonStaticClass=new SignletonStaticClass();
    }

    //4. 公共的静态的实例方法
    public static SignletonStaticClass getInstance(){
        return SignletonStatic.signletonStaticClass;
    }

    //测试方法
    public static void main(String[] args) {
        //利用for循环 模拟多线程环境调用
        for (int i = 0; i < 100; i++) {
            new Thread(()->{
                //看每次获取对象的hashcode是否一致 判断是否获取了同一个对象
                System.out.println("获取的hashCode是: "+SignletonStaticClass.getInstance().hashCode());
            }).start();
        }
    }

}

        Al ejecutar el código de verificación, podemos ver que la seguridad y la eficiencia del subproceso están garantizadas a través de este método de escritura. El principio de este método de escritura es similar al estilo chino hambriento. Usando la función JVN para darse cuenta de que la JVM solo cargará clases e internos clases cuando se están ejecutando Cargue una vez para garantizar la seguridad de subprocesos y la carga diferida.

patrón de estrategia

La estructura del código es la siguiente:

  1. Definir la interfaz de estrategia y definir métodos comunes.
  2. Defina N clases de implementación, implemente la interfaz y vuelva a aplicar el método.
  3. Defina la clase de contexto Contexto y use el polimorfismo para la encapsulación.
  4. Cuando se usa, se llama a través de la clase de contexto Context y el objeto de la clase de implementación se pasa en el constructor.

     Patrón de estrategia: el patrón de estrategia es un patrón de comportamiento que separa los objetos de los comportamientos y define los comportamientos como una interfaz de comportamiento y la implementación de comportamientos específicos. La característica más importante del patrón de estrategia es el cambio de comportamiento, que puede reemplazarse entre sí. Cada juicio if puede entenderse como una estrategia, que puede hacer que el algoritmo cambie independientemente del usuario que lo utilice.

    Escenas a utilizar:

                       1. Suponga que un supermercado ahora tiene tres niveles de miembros, miembros ordinarios, VIP1 y VIP2.

                       2. En el momento del pago, si tres miembros registrados compraron el mismo artículo, no se otorgará ningún descuento a los miembros ordinarios, 10 % de descuento a VIP1 y 20 % de descuento a VIP2

Defina la interfaz de estrategia:

package designmodel.celve;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 12:20 2022/11/8
 * @Param 
 * @return
 * 定义策略接口
 * 案例场景:
 *  有三种会员 购买相同数量和单价的产品时 需要打不同的折扣
 **/
public interface StrategyInt {

    //price价格 n数量
    public double getPrice(double price,int n);
}

Defina miembros ordinarios e implemente la interfaz de estrategia:

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 实现类1 实现接口中定义的计算价格方法
 * 普通会员类 不打折
 **/
public class NormalPerson implements StrategyInt {

    //普通会员不打折
    @Override
    public double getPrice(double price, int n)
    {
        System.out.println("普通会员不打折.....");
        return (price*n);
    }
}

 Defina el miembro vip1 e implemente la interfaz de estrategia:

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *实现类2 实现接口中定义的计算价格方法
 *VIP1会员 打9折
 **/
public class Vip1Person implements StrategyInt{

    //VIP1客户 打9折
    @Override
    public double getPrice(double price, int n) {
        System.out.println("VIP1打9折.....");
        return (price*n)*0.9;
    }
}

 Defina la membresía vip2 e implemente la interfaz de estrategia: 

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 实现类2 实现接口中定义的计算价格方法
 * VIP2会员类 打8折
 **/
public class Vip2Person implements StrategyInt {

    @Override
    public double getPrice(double price, int n) {
        System.out.println("VIP2打8折.....");
        return (price*n)*0.8;
    }
}

Defina la clase de contexto context y use polimorfismo para la encapsulación: 

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 上下文类 对实现类和接口进行封装
 **/
public class PersonContext {
    //1. 定义私有对象
    private StrategyInt strategyInt;

    //2. 定义有参构造方法
    public PersonContext(StrategyInt strategyInt) {
        this.strategyInt = strategyInt;
    }

    //3. 定义计算价格的方法
    public double getPrice(double price,int n){
        return strategyInt.getPrice( price, n);
    }


}

Defina la clase de prueba y llame al método:

package designmodel.celve;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类  演示策略模式的使用场景
 **/
public class StrategyTest {

    public static void main(String[] args) {
        //定义三个类型的对象
        NormalPerson normalPerson = new NormalPerson();
        Vip1Person vip1Person = new Vip1Person();
        Vip2Person vip2Person = new Vip2Person();
        //new context类对象 将三个类型的对象传入
        PersonContext npersonContext = new PersonContext(normalPerson);
        PersonContext v1personContext = new PersonContext(vip1Person);
        PersonContext v2personContext = new PersonContext(vip2Person);
        //利用多态 通过调用context类对象的计算价格方法 实际上调用的子类的计算价格方法 得到最终价格
        System.out.println("普通会员: "+npersonContext.getPrice(300,20));
        System.out.println("VIP1: "+v1personContext.getPrice(300,20));
        System.out.println("VIP2: "+v2personContext.getPrice(300,20));
    }
}

Los resultados de la ejecución son los siguientes:

 

patrón de fábrica

        Creo que todo el mundo ha usado mucho el patrón de fábrica. Este tipo de patrón de diseño pertenece al patrón de creación, que proporciona la mejor manera de crear objetos. En el patrón de fábrica, no expondremos la lógica de creación al cliente al crear objetos. y mediante el uso de una interfaz común para apuntar al objeto recién creado.

       El patrón del método de fábrica se puede utilizar siempre que sea necesario generar objetos complejos. Una cosa a tener en cuenta es que los objetos complejos son adecuados para usar el patrón de fábrica, mientras que los objetos simples, especialmente los objetos que solo necesitan pasar por nuevos unas pocas veces, no se usan. En este caso, no hay necesidad de usar el patrón de fábrica. Si usa el patrón de fábrica, debe introducir una clase de fábrica, lo que aumentará la complejidad del sistema.

fábrica sencilla

        La fábrica simple es una forma simple de escribir el patrón de fábrica. Esta forma de escribir es relativamente simple, pero también trae problemas de acoplamiento. Definamos aviones y automóviles y las clases de fábrica que los producen. El código de implementación principal es el siguiente:

Aeronave:

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 飞机类
 **/
public class Plane {
    public void go(){
        System.out.println("飞机嗖嗖嗖....");
    }
}

Clase de coche:

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 汽车类
 **/
public class Car {
    public void go(){
        System.out.println("汽车滴滴滴....");
    }
}

Clase de fábrica que produce vehículos:

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 工厂类
 **/
public class ProductFactory {

    public Car getCar(){
        return new Car();
    }

    public Plane getPlane(){
        return new Plane();
    }
}

Clase de prueba: 

package designmodel.factory.samplefactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestClass {

    public static void main(String[] args) {
        Car car = new ProductFactory().getCar();
        Plane plane = new ProductFactory().getPlane();
        car.go();
        plane.go();
    }
}

Los resultados de la ejecución son los siguientes:

 

        El método de escritura de esta fábrica simple es relativamente simple y conveniente, pero la desventaja también es obvia, es decir, el grado de acoplamiento entre las clases definidas es demasiado alto. Si se agregan nuevos objetos más tarde, la clase de fábrica debe modificarse muchas veces. veces ¿Cómo resolver esta deficiencia? Ver el patrón de fábrica abstracto.

fábrica abstracta

Escenario de aplicación:

  • Desacoplamiento : Separación de responsabilidades, separando el proceso de creación y uso de objetos complejos .
  • Reutilice el código para reducir los costos de mantenimiento: si la creación del objeto es compleja y debe usarse en varios lugares, si está escrito en cada lugar , se repetirá una gran cantidad de código repetido . Si la lógica comercial cambia , debe modificarse. en todas partes; use el modo de fábrica Para la creación unificada, solo necesita modificar la clase de fábrica para reducir costos. 

La estructura del código es la siguiente:

      Tomemos como ejemplo los vehículos de nueva energía, Wuling y Tesla.

  1. Defina la interfaz del automóvil, y algunos métodos se definen en la interfaz del automóvil, como iniciar, ejecutar y cerrar.
  2. Defina las clases de automóviles de Tesla y Wuling, y anule estos métodos de la interfaz del automóvil.
  3. Defina la interfaz de fábrica para producir automóviles. Hay métodos para producir automóviles en la interfaz, y el tipo de valor devuelto es la interfaz del automóvil.
  4. Defina las clases de fábrica de Tesla y Wuling respectivamente, implemente la interfaz de fábrica para producir automóviles y reescriba los métodos para producir automóviles.
  5. En la clase de prueba, cree directamente las clases de fábrica de Wuling y Tesla, produzca productos relacionados y llame a los métodos de inicio, ejecución y apagado.

Defina la interfaz del coche:

package designmodel.factory.abstractfactory;
/**
 * @Author luocong
 * @Description //TODO
 * @Date 19:35 2022/11/8
 * @Param 
 * @return
 * 定义汽车的接口 汽车可以启动、跑、关闭
 **/
public interface CarProduct {
    //启动
    void start();
    //跑
    void run();
    //关闭
    void shutDown();
}

 Defina la clase de automóvil Tesla e implemente la interfaz del automóvil:

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义具体的实现类
 * 特斯拉汽车
 **/
public class TeslaCar implements CarProduct {
    @Override
    public void start() {
        System.out.println("特斯拉启动了");
    }

    @Override
    public void run() {
        System.out.println("特斯拉跑了");
    }

    @Override
    public void shutDown() {
        System.out.println("特斯拉关闭了");
    }
}

Defina la clase de automóvil Wuling para implementar la interfaz del automóvil:

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义具体的实现类
 * 五菱汽车
 **/
public class WulingCar implements CarProduct {
    @Override
    public void start() {
        System.out.println("五菱启动了");
    }

    @Override
    public void run() {
        System.out.println("五菱开始跑了");
    }

    @Override
    public void shutDown() {
        System.out.println("五菱关闭了");
    }
}

Defina una clase de fábrica que produzca automóviles: 

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义生产汽车的工厂类
 *
 **/
public interface CarproductFactory {

    CarProduct productCar();
}

Defina la clase de fábrica que produce Wuling Motors: 

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义生产五菱的汽车工厂
 * 生成五菱汽车的对象
 **/
public class WuLingFactory implements CarproductFactory {
    @Override
    public CarProduct productCar() {
        return new WulingCar();
    }
}

Defina la clase de fábrica que produce Tesla:

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义特斯拉汽车的工厂
 * 生产特斯拉汽车
 **/
public class TeslaFactory implements CarproductFactory {
    @Override
    public CarProduct productCar() {
        return new TeslaCar();
    }
}

Clase de prueba: 

package designmodel.factory.abstractfactory;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TestFactory {

    public static void main(String[] args) {
        //生产五菱汽车
        WuLingFactory wuLingFactory = new WuLingFactory();
        CarProduct carProduct = wuLingFactory.productCar();
        carProduct.start();
        carProduct.run();
        carProduct.shutDown();
        System.out.println("*******************************");
        //生产特斯拉汽车
        TeslaFactory teslaFactory = new TeslaFactory();
        CarProduct carProduct1 = teslaFactory.productCar();
        carProduct1.start();
        carProduct1.run();
        carProduct1.shutDown();
    }
}

   Los resultados de la ejecución son los siguientes:

        A través de la fábrica abstracta, podemos reducir el acoplamiento entre códigos. Por ejemplo, si agregamos la clase de automóvil Xiaopeng en el futuro, podemos agregar directamente la clase de fábrica de la clase de automóvil Xiaopeng y la clase de automóvil Xiaopeng. Este método de implementación es beneficioso al negocio expandir.

modo fachada

        Patrón de Fachada: También llamado Patrón de Apariencia, se requiere que la comunicación entre el exterior de un subsistema y su interior se realice a través de un objeto unificado. El patrón Facade proporciona una interfaz de alto nivel que facilita el uso del subsistema.

Escena aplicable:

        Existe una fuerte relación de dependencia entre múltiples clases de subsistemas, y la invocación de relaciones complejas se maneja de manera uniforme a través de la clase de fachada.Cuando se llama a la clase externa, se puede llamar a la clase de fachada sin llamar a la clase de subsistema.

 El modo fachada es relativamente simple y la implementación del código es la siguiente:

Defina la clase de sistema A y comuníquese con el sistema A a través de la clase A:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟系统类A
 * 假设A系统类中有方法doA
 **/
public class SystemA {
    public String doA(){
        return "A";
    }
}

Defina la clase B del sistema y comuníquese con el sistema A a través de la clase B:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟系统类B
 * 假设A系统类中有方法doB
 **/
public class SystemB {
    public String doB(){
        return "B";
    }
}

Defina la clase del sistema C y comuníquese con el sistema A a través de la clase C:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟系统类C
 * 假设A系统类中有方法doC
 **/
public class SystemC {
    public String doC(){
        return "C";
    }
}

Defina la clase de fachada y realice las llamadas complejas entre los tres sistemas A, B y C a través de la clase de fachada:

package designmodel.doormodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 门面模式中的门面类 可以通过此类实现系统A、B、C之间的复杂关系调用
 **/
public class ControlClas {

    //私有化三个系统的类
    private SystemA systemA=new SystemA();
    private SystemB systemB=new SystemB();
    private SystemC systemC=new SystemC();

    //通过此方法实现A、B、C之间的复杂调用
    public void doSomthing(){
        //自定义逻辑
        systemA.doA();
        //自定义逻辑
        systemB.doB();
        //自定义逻辑
        systemC.doC();
    }

}

         Podemos ver que a través de la última clase de control, podemos controlar la escena compleja donde los sistemas A, B y C se llaman entre sí, y cuando la clase externa llama a A, B y C para implementar el negocio, podemos llamar directamente al clase de fachada a implementar, sin definir códigos complejos en A, B y C.

patrón decorador

        El patrón decorador es un patrón estructural de objetos que agrega dinámicamente responsabilidades/funciones a los objetos de una manera que no requiere definir subclases y usa la relación de asociación entre objetos para reemplazar la relación de herencia entre clases. 

 Los escenarios de aplicación son los siguientes:

   Por ejemplo:

       Por ejemplo, Wuling Motors, Wuling Motors puede funcionar primero, y esta característica es una característica invariable.

       Otros modelos son diferentes, como diferente duración de la batería, si es convertible, si tiene voz inteligente, etc.

       Las interfaces se pueden definir para funciones que no cambian, y los decoradores se pueden definir para funciones cambiantes.Los decoradores agregan algunas modificaciones al original.

La estructura del código es la siguiente:

  1. Definir clase abstracta de Wuling Motors, método general
  2. Defina la versión convertible y la versión de gameboy para heredar a la clase abstracta de Wuling Motors y reescriba el método general.
  3. Defina la clase de decorador de Wuling, heredé de la clase abstracta de Wuling Auto, pase el objeto del tipo abstracto de Wuling Auto y llame al método general del tipo abstracto de Wuling Auto.
  4. Defina el decorador convertible y el decorador de mejora de la duración de la batería de Wuling Motors por separado, herede la clase de decorador de Wuling Motors, reescriba el método general y aumente la función de decorador.
  5. A través de la llamada de clase de prueba, el nuevo objeto convertible de Wuling se pasa al decorador convertible y se llama al método de ejecución del decorador.

Defina la clase abstracta de Wuling New Energy Vehicle y defina el método de ejecución:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 五菱新能源汽车
 **/
public abstract class WulingNewEngeryCar {

    abstract void run();
}

Defina el modelo específico de Wuling New Energy, como gameboy, que se hereda de Wuling New Energy:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 五菱gameBoy
 **/
public class WulingGameBoy extends WulingNewEngeryCar {
    @Override
    void run() {
        System.out.println("五菱gameBoy");
    }
}

Defina el modelo específico de Wuling New Energy, como la versión convertible, que se hereda de Wuling New Energy:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 五菱敞篷版
 **/
public class Wulingchangpeng  extends  WulingNewEngeryCar{
    @Override
    void run() {
        System.out.println("敞篷版五菱");
    }
}

 Defina la clase de decoración de Wuling New Energy Vehicle, que también hereda de la nueva clase de energía:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义五菱汽车的装饰器类
 **/
public abstract class WulingDecorate extends WulingNewEngeryCar{
    //私有的对象
    private WulingNewEngeryCar wulingNewEngeryCar;
    //公共的构造函数
    public WulingDecorate(WulingNewEngeryCar wulingNewEngeryCar) {
        this.wulingNewEngeryCar = wulingNewEngeryCar;
    }
    //重写汽车的能力
    @Override
    void run() {
        wulingNewEngeryCar.run();
    }
}

Defina la clase de decoración de Wuling Convertible, heredada de la clase de decoración de Wuling Automóvil:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 敞篷装饰器
 **/
public class NoDoorDecorate extends WulingDecorate{

    //调用父类的构造方法
    public NoDoorDecorate(WulingNewEngeryCar wulingNewEngeryCar) {
        super(wulingNewEngeryCar);
    }

    //增加装饰
    @Override
    void run() {
        super.run();
        System.out.println("增加敞篷功能");
    }
}

Defina la clase de decoración de la versión de duración de la batería de Wuling, heredada de la clase de decoración de Wuling Motors:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 续航增强装饰器
 **/
public class RunLongDecorate extends WulingDecorate{
    public RunLongDecorate(WulingNewEngeryCar wulingNewEngeryCar) {
        super(wulingNewEngeryCar);
    }

    @Override
    void run() {
        super.run();
        System.out.println("续航增强");
    }

}

Clase de prueba:

package designmodel.decoratemodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class AppTestClass {
    public static void main(String[] args) {
        //new 一个wuling敞篷类
        Wulingchangpeng wulingchangpeng=new Wulingchangpeng();
        //调用敞篷装饰器 增加敞篷功能
        NoDoorDecorate noDoorDecorate = new NoDoorDecorate(wulingchangpeng);
        noDoorDecorate.run();
        RunLongDecorate runLongDecorate1 = new RunLongDecorate(wulingchangpeng);
        runLongDecorate1.run();
        System.out.println("*****************");
        WulingGameBoy wulingGameBoy = new WulingGameBoy();
        RunLongDecorate runLongDecorate = new RunLongDecorate(wulingGameBoy);
        runLongDecorate.run();
    }
}

Los resultados de la ejecución son los siguientes:

        Podemos ver que la ventaja del modo decorador es que encapsula el método de ejecución inalterable y luego lo mejora según el método de ejecución, para satisfacer las necesidades de diferentes formas de mejorar ciertos métodos en diferentes escenarios.Si otro modelo es agregado, entonces solo necesita agregar clases de modelo y clases de decorador específicas, lo que reduce en gran medida el acoplamiento de códigos y al mismo tiempo satisface la mejora de métodos.

modelo de cadena de responsabilidad

        El patrón de diseño Cadena de responsabilidad es un patrón de diseño común en el desarrollo de software. En este patrón, una solicitud se procesa progresivamente para formar una cadena, y la solicitud se procesa en los nodos de la cadena. Después de que un nodo procesa su propia lógica, se pasa al en el siguiente nodo.

Escenario de aplicación:

         Al tratar con la información del mensaje transmitida por la página web, la información del mensaje será procesada. Algunas clases son responsables de procesar caracteres especiales en el mensaje, y algunas clases son responsables de procesar información como palabras confidenciales en el mensaje. Esta situación es aplicable en el modelo de cadena de responsabilidad.

La estructura del código es la siguiente:

  1. Definir la clase principal para filtrar
  2. Defina dos subclases para heredar de la clase principal y reescriba el método de filtrado
  3. Defina la cadena de clase de responsabilidad, pase las dos subclases y llame al método de filtro de las subclases.
  4. Pase la subclase a través de la clase de prueba, llamando al método de filtro.

 Defina una interfaz para el manejo de mensajes:

package designmodel.responsiblity;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 11:06 2022/11/9
 * @Param 
 * @return
 * 定义处理消息的接口
 **/
public interface FatherFilter {
    //定义处理消息的方法
    public String doFilter(String msg);
}

Defina una clase para filtrar caracteres especiales e implemente una interfaz para procesar mensajes:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 处理http消息的类
 * 过滤http消息
 **/
public class HttpFilter implements FatherFilter{

    @Override
    public String doFilter(String msg) {
        String replace = msg.replace("-", "");
        System.out.println("HttpFilter replace msg: "+replace);
        return replace;
    }
}

Defina la clase que maneja palabras confidenciales e implemente la interfaz para procesar mensajes:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 处理消息的类
 * 过滤消息
 **/
public class MsgFilter implements FatherFilter{

    @Override
    public String doFilter(String msg) {
        String replace = msg.replace("*", "");
        System.out.println("MsgFilter replace msg: "+replace);
        return replace;
    }
}

        Defina la cadena de clase base de responsabilidad, defina la colección y almacene los objetos cuyo tipo genérico es la interfaz de mensaje en la colección. Al llamar a la cadena de clase de responsabilidad, haga un bucle en la colección y llame al método de filtro de punto de objeto:

package designmodel.responsiblity;

import java.util.ArrayList;
import java.util.List;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 责任链基类
 **/
public class FatherFilterChain {

    //储存http和msg的filter
    List<FatherFilter> list=new ArrayList<FatherFilter>();

    //添加filter
    public void add(FatherFilter fatherFilter){
        list.add(fatherFilter);
    }

    //定义执行过滤的方法
    public void doFilter(String msg){
        for (int i = 0; i < list.size(); i++) {
            msg = list.get(i).doFilter(msg);

        }
    }


}

Defina la clase de mensaje y almacene el mensaje:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模拟传递消息的类
 **/
public class Msg {
    private String msg;

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return msg;
    }
}

Clase de prueba:

package designmodel.responsiblity;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestResponsiblity {

    public static void main(String[] args) {
        //定义消息类
        Msg msg = new Msg();
        msg.setMsg("你好,------,我是***琪琪.....");
        //new http处理对象和msg处理对象
        HttpFilter httpFilter = new HttpFilter();
        MsgFilter msgFilter = new MsgFilter();
        //new 责任链处理对象
        FatherFilterChain fatherFilterChain = new FatherFilterChain();
        //将http处理对象和msg处理对象加入责任链
        fatherFilterChain.add(httpFilter);
        fatherFilterChain.add(msgFilter);
        //传递消息 执行过滤
        fatherFilterChain.doFilter(msg.getMsg());

    }
}

Los resultados de la ejecución son los siguientes:

         Podemos ver que el llamado patrón de Cadena de Responsabilidad, para decirlo sin rodeos, usa las características del polimorfismo, encapsula objetos en colecciones y llama al método del objeto en un bucle cuando llama a un método, y usa el bucle para llamar El escenario típico de aplicación del patrón Chain of Responsibility es The filter class of spring, si estás interesado, puedes mirar el código fuente.

modo de peso mosca

        Modo Flyweight:  al compartir objetos existentes, la cantidad de objetos que deben crearse se reduce considerablemente y se evita la sobrecarga de una gran cantidad de objetos similares, lo que mejora la tasa de utilización de los recursos del sistema y el contenido recurrente se elimina como una parte compartida y compartida por varios objetos Una copia, lo que reduce la presión sobre la memoria

Escenario de aplicación:

        La implementación de String es el modo Flyweight. Hay un grupo de constantes para varios caracteres en la capa inferior. Cuando una variable se refiere a una constante, se refiere directamente a la constante en el grupo de constantes. Otro ejemplo es el grupo de conexión de la base de datos, que también utiliza el modo Flyweight.

Veamos la implementación del código de la conexión de base de datos simulada:

Defina la clase base del recurso de conexión a la base de datos. Otras clases deben heredar esta clase:

package designmodel.enjoymodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义数据库连接资源基类 其他类需要继承此类
 **/
public abstract class DataSource {
    String dataId;
    String dataName;

    public String getDataId() {
        return dataId;
    }

    public String getDataName() {
        return dataName;
    }

    public void setDataId(String dataId) {
        this.dataId = dataId;
    }

    public void setDataName(String dataName) {
        this.dataName = dataName;
    }

    public DataSource(String dataId, String dataName) {
        this.dataId = dataId;
        this.dataName = dataName;
    }
    public abstract void method();

    @Override
    public String toString() {
        return "DataSource{" +
                "dataId='" + dataId + '\'' +
                ", dataName='" + dataName + '\'' +
                '}';
    }
}

Defina la clase de productor de objetos de la base de datos:

package designmodel.enjoymodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 数据库连接生产者类1
 **/
public class DataSourceMaker extends DataSource{

    public DataSourceMaker(String dataId, String dataName) {
        super(dataId, dataName);
    }

    @Override
    public void method() {
        System.out.println("使用DataSourceMaker1生产数据库连接对象.....");
    }
}

Defina la clase de fábrica para producir objetos de conexión de base de datos:

package designmodel.enjoymodel;

import java.util.HashMap;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 数据库连接工厂 生产数据库连接对象
 *
 **/
public class DataSourceFactory {
    private static HashMap<String,DataSource> hashMap=new HashMap<>();

    public DataSourceFactory() {
        for (int i = 0; i < 10; i++) {
            DataSourceMaker dataSourceMaker = new DataSourceMaker(String.valueOf(i), "DataSource" + i);
            hashMap.put(dataSourceMaker.getDataId(),dataSourceMaker);
        }
    }



    public DataSource getDataSourceFactory(String datasourceName){
        if (hashMap.containsKey(datasourceName)){
            return hashMap.get(datasourceName);
        }
        return null;
    }
}

Defina la clase de prueba:

package designmodel.enjoymodel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TestDataSource {

    public static void main(String[] args) {
        //取出数据库连接对象
        DataSourceFactory dataSourceFactory = new DataSourceFactory();
        for (int i = 0; i < 10; i++) {
            System.out.println("i: "+dataSourceFactory.getDataSourceFactory(String.valueOf(i)).toString());
        }
    }
}

Los resultados de la ejecución son los siguientes:

 

         Se puede ver que el propósito principal del patrón Flyweight es construir el concepto de un grupo. Cuando necesite usar el objeto, puede obtenerlo del grupo. No necesita crear el objeto varias veces. puede verlo en la implementación del grupo de conexiones de la base de datos.

Patrón de observador

        El modo de observador (Observer) , también conocido como modo de publicación-suscripción (Publicar/Suscribir) , define una relación de dependencia de uno a muchos (registro) entre objetos, de modo que cada vez que un objeto cambia de estado, todos los objetos que dependen de él obtendrán notificado y actualizado automáticamente (notificaciones). Para decirlo sin rodeos, es un proceso de registro y notificación.

La estructura del código es la siguiente:

  1. Defina la interfaz del observador y los métodos del observador.
  2. Definir las clases de implementación A y B de la interfaz
  3. Defina la clase de tema y pase al observador a una colección.
  4. Llame al método de notificación, haga un bucle en el observador y pase los parámetros al observador para que responda.

        El siguiente código se usa para simular el movimiento entre el capital especulativo y los fondos cuando el mercado de valores está cambiando. Esta escena puede mostrar vívidamente el modo observador:

Defina la interfaz del observador del mercado de valores:

package designmodel.watcher;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 12:01 2022/11/9
 * @Param 
 * @return
 * 定义股票观察者父类
 **/
public interface SharsObserver {

    //观察之后做出如何反映
    public void response(int i);
}

Defina la clase de capital especulativo e implemente la interfaz de observador:

package designmodel.watcher;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 个人股民
 **/
public class PersonObserver implements SharsObserver{
    @Override
    public void response(int i) {
        if(i>0){
            System.out.println("游资: 涨了,快点投资投资.......");
        }else{
            System.out.println("游资: 跌了,快点撤资撤资.......");
        }
    }
}

Defina la clase de fondo e implemente la interfaz de observador:

package designmodel.watcher;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class CompanyObserver implements SharsObserver {
    @Override
    public void response(int i) {
        if(i>0){
            System.out.println("机构: 涨了,再拉点投资吧.......");
        }else{
            System.out.println("机构: 跌了,稳一点,先不动.......");
        }

    }
}

 Defina la clase de sujeto para ensamblar la dinámica del observador:

package designmodel.watcher;

import designmodel.responsiblity.FatherFilter;

import java.util.ArrayList;
import java.util.List;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义主题类型
 * 其中定义可以新增删除 通知观察者的方法
 **/
public class Subject {

    //储存游资和基金的对象
    List<SharsObserver> list=new ArrayList<SharsObserver>();

    //新增观察者
    public void addObserver(SharsObserver sharsObserver){
        list.add(sharsObserver);
    }

    //通知观察者
    public void change(int j){
        for (int i = 0; i < list.size(); i++) {
            SharsObserver sharsObserver = list.get(i);
            sharsObserver.response(j);
        }
    }
}

Clase de prueba:

package designmodel.watcher;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestMain {

    public static void main(String[] args) {
        CompanyObserver companyObserver = new CompanyObserver();
        PersonObserver personObserver = new PersonObserver();
        Subject subject = new Subject();
        subject.addObserver(companyObserver);
        subject.addObserver(personObserver);
        subject.change(2);
        System.out.println("---------------------");
        subject.change(0);

    }
}

Los resultados de la ejecución son los siguientes:

 

         Como puede ver en el código, el patrón de observador es similar al patrón de cadena de responsabilidad, por lo que el patrón de observador generalmente se usa junto con el patrón de cadena de responsabilidad.

modo proxy

        El modo proxy es un modo de diseño de Java comúnmente utilizado. Su característica es que la clase proxy tiene la misma interfaz que la clase delegada. La clase proxy es principalmente responsable de preprocesar mensajes para la clase delegada, filtrar mensajes, reenviar mensajes a la clase delegada. y procesar mensajes después del evento.

modo proxy estático

        El proxy estático es un modo de implementar el proceso de proxy a través de una clase personalizada. Solo puede representar esta clase. Si desea representar otras clases, debe escribir un nuevo método de proxy si desea representar otras clases.

La estructura del código es la siguiente:

  1. Definir la interfaz del coche
  2. Defina la clase de implementación de la interfaz del automóvil para realizar la interfaz del automóvil.
  3. Defina la clase de proxy del automóvil e implemente la interfaz del automóvil.
  4. Inyecte el objeto del tipo de interfaz en la clase de proxy, llame al método de ejecución y realice la llamada del nuevo método antes y después del método de ejecución

Defina la interfaz del coche:

package designmodel.poxymodel.staticpoxy;
/***
 * @Author luocong
 * @Description //TODO
 * @Date 17:02 2022/11/9
 * @Param 
 * @return
 * 定义汽车类
 **/
public interface CarInterface {
    //汽车可以跑
    public void run();
}

Defina la clase de automóvil e implemente la interfaz del automóvil:

package designmodel.poxymodel.staticpoxy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class Car implements CarInterface {

    @Override
    public void run() {
        System.out.println("汽车在跑.......");
    }
}

Defina la clase de proxy del automóvil y también implemente la interfaz del automóvil:

package designmodel.poxymodel.staticpoxy;

import designmodel.poxymodel.staticpoxy.Car;
import designmodel.poxymodel.staticpoxy.CarInterface;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义汽车的代理对象 代理对象也实现汽车接口
 **/
public class Carproxy  implements CarInterface {
    //私有化汽车类
    private Car car;
    //创建构造函数
    public Carproxy(Car car) {
        this.car = car;
    }
    //调用汽车类的run方法 在run之前和之后可以定义新方法
    @Override
    public void run() {
        beforeRun();
        car.run();
        afterRun();
    }

    //汽车运行之前调用的方法
    private void afterRun() {
        System.out.println("汽车打开火了.....");
    }

    //汽车运行之后调用的方法
    private void beforeRun() {
        System.out.println("汽车熄火了.....");
    }
}

Clase de prueba: 

package designmodel.poxymodel.staticpoxy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestMain {
    public static void main(String[] args) {
        Carproxy carproxy = new Carproxy(new Car());
        carproxy.run();
    }
}

Resultados de la:

 

        A través del proxy estático, podemos simplemente realizar el proxy de una determinada clase e interfaz, pero el proxy estático también tiene ciertas limitaciones.Si necesitamos representar una nueva clase, necesitamos que la clase proxy implemente una nueva interfaz para reescribir algunos métodos, esto obviamente es un inconveniente, por lo que JDK nos proporciona un método de proxy dinámico.

Modo proxy dinámico

        El proxy dinámico es implementado por JDK para nosotros. Su principio se basa en la reflexión de clase, genera dinámicamente una clase de proxy para nosotros y nos ayuda a ejecutar métodos. Podemos definir algunos métodos personalizados antes y después de que se ejecute el método. Veámoslo a continuación. Estructura del código:

  1. Definir la interfaz del coche
  2. Defina la clase de implementación de la interfaz del automóvil para realizar la interfaz del automóvil.
  3. Defina la clase de proxy, inyecte el objeto del tipo de interfaz, llame al método newProxyInstence del Proxy, pase object.getclass.getclassloader, pase object.getClass.getInterfaces, pase la clase interna InvocationHandler e implemente la llamada en la clase interna.

Defina la interfaz del coche:

package designmodel.poxymodel.movepoxy;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 17:15 2022/11/9
 * @Param
 * @return
 * 定义汽车接口
 **/
public interface CarInterface {
    public void run();
}

Defina la clase de automóvil e implemente la interfaz:

package designmodel.poxymodel.movepoxy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 汽车类实现了汽车接口 重写run方法
 **/
public class Car  implements CarInterface{

    @Override
    public void run() {
        System.out.println("汽车跑起来了......");
    }
}

Defina la clase de proxy de la clase de automóvil (también se puede implementar directamente en la clase de prueba, la función principal es encapsular el proceso de proxy):

package designmodel.poxymodel.movepoxy;

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

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义汽车的动态代理类
 **/
public class CarMoveProxy {


    //利用JDK的动态代理实现代理模式
    public void doRun(Car car,InvocationHandler invocationHandler){
        //第一个参数 对象.getClass.getClassLoder 第二个参数 对象.getCalss.getInterfaces 第三个参数 invocationHandler内部类
        CarInterface car1= (CarInterface) Proxy.newProxyInstance(car.getClass().getClassLoader(),
                car.getClass().getInterfaces(),
                invocationHandler);
        car1.run();
    }
}

Clase de prueba:

package designmodel.poxymodel.movepoxy;

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

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 测试类
 **/
public class TestProxy {
    public static void main(String[] args) {
        CarMoveProxy carMoveProxy = new CarMoveProxy();
        Car car = new Car();
        carMoveProxy.doRun(car, new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                System.out.println("汽车启动...");
                Object invoke = method.invoke(car, objects);
                System.out.println("汽车关闭...");
                return invoke;
            }
        });
    }
}

Los resultados de la ejecución son los siguientes:

 

        El resultado de la ejecución es el mismo que el del proxy estático, pero podemos entenderlo a través del código. La única diferencia es que el proxy dinámico no requiere que personalicemos la clase de proxy. La segunda es que una clase de proxy se genera dinámicamente. para nosotros a través del mecanismo de reflejo de Java para ejecutar nuestro método de definición.

patrón de adaptador

        Convierte la interfaz de una clase a otra interfaz que el cliente quiera. El patrón de adaptador permite que las clases que de otro modo no funcionarían juntas debido a interfaces incompatibles trabajen juntas

        El llamado adaptador consiste en ensamblar diferentes tipos de interfaces de cierta manera. Por ejemplo, el convertidor de línea de datos que encontramos en nuestra vida puede convertir diferentes tipos de interfaces en las interfaces que necesitamos. El modo adaptador generalmente se aplica a nuevos y viejos proyectos En el caso de la coexistencia, los códigos de diferentes métodos de escritura en los proyectos nuevos y antiguos se pueden convertir.

patrón de adaptador de objeto

 Inyecte el objeto y complete la conversión del adaptador. La estructura del código es la siguiente: 

  1. Definir interfaz TYPEC
  2. Definir clase TYPEA
  3. Defina la clase de adaptador e implemente la interfaz TYPEC
  4. Rellene el objeto de TypeA como un atributo y reescriba el método de la interfaz
  5. El método de typeA se puede llamar en el método de la interfaz

Defina la interfaz typC:

package designmodel.adapter.objectadapter;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 18:04 2022/11/9
 * @Param 
 * @return
 * 定义typeC接口
 **/
public interface TypeCInterface {

    //输出5V的电压
    public void v5();
}

Defina la clase typeA:

package designmodel.adapter.objectadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TypeA {
    public void v220(){
        System.out.println("输出220V电压");
    }
}

Defina la clase de adaptador, implemente la interfaz typeC e inyecte el objeto TypeA:

package designmodel.adapter.objectadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义适配器类 实现typeC接口
 **/
public class PowerAdapter implements TypeCInterface{

    public TypeA typeA=new TypeA();

    public PowerAdapter(TypeA typeA) {
        this.typeA = typeA;
    }

    @Override
    public void v5() {
        typeA.v220();
    }
}

Clase de prueba:

package designmodel.adapter.objectadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TestAdapter {
    public static void main(String[] args) {
        PowerAdapter powerAdapter = new PowerAdapter(new TypeA());
        powerAdapter.v5();
    }
}

Resultados de la:

         Se puede ver que debido a la inyección del objeto typA, al llamar al método de v5, debería generar un voltaje de 5 V, pero ahora podemos generar un voltaje de 220 V, que es el modo adaptador del objeto.

patrón de adaptador de clase

Use herencia e implementación para completar la conversión del adaptador, la estructura del código es la siguiente:

  1. definir interfazA
  2. definir la clase B
  3. Defina la clase de adaptador C para heredar de B para implementar la interfaz A
  4. En la clase adaptadora, tanto el método de la interfaz A como el método de la clase B se pueden reescribir

Defina la interfaz TypeC:

package designmodel.adapter.classadapter;

/**
 * @Author luocong
 * @Description //TODO
 * @Date 18:04 2022/11/9
 * @Param 
 * @return
 * 定义typeC接口
 **/
public interface TypeCInterface {

    //输出5V的电压
    public void v5();
}

Defina la clase typeA:

package designmodel.adapter.classadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 **/
public class TypeA {
    public void v220(){
        System.out.println("输出220V电压");
    }
}

Defina la clase de adaptador:

package designmodel.adapter.classadapter;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 定义类适配器 实现接口并继承类 在重写的方法中可以输出220v电压
 * 并且可以定义输出5v电压的逻辑
 **/
public class PowerAdapter extends TypeA implements TypeCInterface{
    @Override
    public void v5() {
        this.v220();
    }

    @Override
    public void v220() {
        super.v220();
    }
}

        Se puede ver que la mayor diferencia entre estos dos modos de implementación es que uno es inyectar objetos para implementar interfaces, y el otro es heredar clases para implementar interfaces. En el proceso de uso, generalmente se recomienda el primer método. La herencia aumentar la carga hasta cierto punto Acoplamiento entre clases. 

patrón de prototipo

        El modo de prototipo (modo de prototipo) se refiere a: use la instancia de prototipo para especificar el tipo de objeto que se creará y cree nuevos objetos copiando estos prototipos, y la copia se divide en copia superficial y copia profunda.

        La llamada copia superficial consiste en copiar un objeto en otro objeto, pero las propiedades del objeto apuntan a lo mismo. Si se cambia cualquier objeto, las propiedades de los dos objetos cambiarán en consecuencia.

        La copia profunda es usar el flujo IO para copiar un objeto. Al modificar las propiedades de cualquier objeto, las propiedades de otro objeto no cambiarán.

Escena aplicable:

        requieren un uso extensivo de un objeto

La estructura de implementación de la copia superficial es la siguiente:

  1. Defina la clase Wukong, defina atributos, métodos de construcción, métodos tostring e implemente la interfaz clonable
  2. Llame al método super.clone para clonar el objeto
  3. Modifique el objeto 2 en este momento, y las propiedades del objeto 1 cambiarán en consecuencia

La estructura de implementación de la copia profunda es la siguiente:

  1. Defina la clase Wukong, defina atributos, métodos de construcción, métodos tostring e implemente la interfaz clonable
  2. Escribe el objeto actual en la secuencia y vuelve a escribir el objeto a través de la secuencia.
  3. Modifique ahora el objeto 2. Las propiedades del objeto 1 no cambiarán en consecuencia.

El código para la copia superficial es el siguiente:

package designmodel.prototype.shallowcopy;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 猴王类 定义悟空的属性 重写克隆方法
 **/
public class KingMonkey implements Cloneable{
    private String name="孙悟空";
    private int age=5000;
    private String skill="七十二变";

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getSkill() {
        return skill;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public KingMonkey(String name, int age, String skill) {
        this.name = name;
        this.age = age;
        this.skill = skill;
    }

    public KingMonkey() {
    }

    @Override
    public String toString() {
        return "KingMonkey{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", skill='" + skill + '\'' +
                '}';
    }

    //重写clone方法
    @Override
    protected KingMonkey clone() throws CloneNotSupportedException {
        return (KingMonkey)super.clone();
    }
}

El código para la copia profunda es el siguiente:

package designmodel.prototype.deepcopy;


import java.io.*;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 新的猴王类 将param封装为自己的属性
 **/
public class KingMonkey1 implements Cloneable,Serializable{
    private String name="孙悟空";
    private int age=5000;
    private String skill="七十二变";

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setSkill(String skill) {
        this.skill = skill;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getSkill() {
        return skill;
    }

    @Override
    public String toString() {
        return "KingMonkey1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", skill='" + skill + '\'' +
                '}';
    }

    public KingMonkey1() {
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            //将对象写入字节流
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(this);
            //把字节流转化为对象
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            System.out.println("走进来了.....");
            KingMonkey1 kingMonkey1 = (KingMonkey1) ois.readObject();
            return kingMonkey1;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

patrón de método de plantilla

Define el esqueleto         de un algoritmo en una operación , delegando algunos pasos a las subclases. Permite que las subclases redefinan algunos pasos específicos de un algoritmo sin cambiar la estructura del algoritmo.

Escenario de aplicación:

        Por ejemplo, para generar una plantilla PDF, hay posiciones de logotipo fijas y diseños de tablas. Lo que no es fijo es el análisis de datos. Puede colocar la posición del logotipo y el estilo básico en la clase principal y colocar el análisis de datos en la subclase.

La estructura del código es la siguiente:

  1. Defina una clase principal abstracta, defina atributos y métodos en ella y encapsule el formato sin cambios.
  2. Defina una subclase, herede la clase principal, reescriba algunos métodos, agregue su propia lógica, llame al método total de la clase principal y complete el procesamiento.
  3. Defina la clase de prueba y complete la lógica llamando al método de la clase principal a través de la subclase

Defina una clase de plantilla:

package designmodel.templeteModel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 * 模板类
 **/
public abstract class TempleteClass {
    //基本方法
    protected abstract void doA();
    protected abstract void doB();

    //模板方法
    public void templeteMethod(){
        doA();
        if(isDoAnything()){
            doB();
        }
    }
    //返回布尔值
    public boolean isDoAnything(){
        return true;
    }

}

Defina la implementación del método de la subclase:

package designmodel.templeteModel;

/**
 * @{NAME}
 * @Description TODO
 * @Author luocong
 * @Date
 * @Version 1.0
 *子类
 **/
public class TempleteChild extends TempleteClass{

    @Override
    protected void doA() {
        System.out.println("进入了A方法");
    }

    @Override
    protected void doB() {
        System.out.println("进入了B方法");
    }

    @Override
    public boolean isDoAnything() {
        return true;
    }

    public void doAllthings(){
        super.templeteMethod();
    }
}

A través del patrón de método de plantilla, el algoritmo que se considera como la parte invariable se puede encapsular en la clase principal para su implementación, mientras que la parte variable puede continuar ampliándose a través de la herencia. El comportamiento es controlado por la clase principal e implementado por la subclase. . Los métodos básicos se implementan mediante subclases, por lo que las subclases pueden agregar funciones correspondientes a través de extensiones, lo que se ajusta al principio de apertura y cierre.

Supongo que te gusta

Origin blog.csdn.net/weixin_43195884/article/details/127759687
Recomendado
Clasificación