Patrones de diseño de Java: principios de diseño de software y siete patrones de diseño de uso común

prefacio

Los patrones de diseño son soluciones a problemas comunes en el desarrollo de software y son 经过验证的并且经常被重复使用的设计模板. Los patrones de diseño proporcionan un conjunto de soluciones comunes para ayudar a los desarrolladores a estructurar 高质量、可维护和可扩展el código.设计模式并不是特定于某种编程语言,而是面向对象编程范式的通用原则

1. Tipos de patrones de diseño

Patrones creacionales

Este tipo de patrón de diseño 关注如何创建对象,. 旨在解决对象创建的灵活性和复杂性Incluyendo 单例模式、工厂模式、抽象工厂模式, modo constructor y modo prototipo

  • Patrón Singleton: garantizar una clase 只有一个实例y proporcionar un punto de acceso global
  • Patrón de fábrica: defina una interfaz para crear objetos, definida por子类决定要实例化的类
  • Abstract Factory Pattern: proporciona una interfaz para crear familias de objetos relacionados o dependientes sin especificar clases concretas explícitamente
  • Patrón constructor (Builder Pattern): a 复杂对象的构建与其表示分离, para que el mismo proceso de construcción pueda crear diferentes representaciones
  • Prototipo de patrón: cree nuevos objetos copiando objetos existentes sin conocer sus clases concretas

Patrones Estructurales

Este tipo de patrón de diseño se refiere a 如何将类和对象组合成更大的结构,以解决系统中不同类和对象之间的灵活性和复杂性问题. Incluyendo el modo adaptador, el modo decorador, el modo proxy, el modo compuesto, el modo fachada, el modo puente y el modo peso mosca

  • Patrón adaptador: convierte la interfaz de una clase en otra interfaz esperada por el cliente
  • Patrón de decorador: agregue dinámicamente responsabilidades a los objetos para ampliar la funcionalidad
  • Patrón de proxy: proporcione un proxy para que otros objetos controlen el acceso a este objeto
  • Patrón compuesto: combinación de objetos en una estructura de árbol para representar una jerarquía de "parte-todo"
  • Patrón de fachada: proporciona una interfaz unificada para acceder a un grupo de interfaces en el subsistema
  • Bridge Pattern: Separa la abstracción de su implementación para que puedan variar de forma independiente
  • Patrón de peso ligero: reduzca el uso de memoria al compartir objetos

Patrones de comportamiento

Este tipo de patrón de diseño 关注对象之间的通信和职责分配,以解决类和对象之间的高效沟通和合作问题incluye patrón de observador, patrón de estrategia, patrón de comando, patrón de método de plantilla, patrón de iterador, patrón de cadena de responsabilidad, patrón de estado y patrón de visitante.

  • Patrón de observador (Patrón de observador): define una relación de dependencia de uno a muchos. Cuando el estado de un objeto cambia, todos sus objetos dependientes serán notificados y actualizados automáticamente.
  • Patrón de estrategia: defina una serie de algoritmos, encapsule cada algoritmo y hágalos intercambiables
  • Patrón de comando: encapsule la solicitud en un objeto, de modo que se puedan parametrizar diferentes solicitudes y admita la puesta en cola, el registro y la revocación de solicitudes.
  • Patrón de método de plantilla: defina el esqueleto de un algoritmo, delegando algunos pasos a las subclases
  • Patrón de iterador: proporciona una forma de acceder secuencialmente a los elementos en un objeto agregado
  • Patrón de cadena de responsabilidad (Chain of Responsibility Pattern): desacopla el envío y la recepción de solicitudes, lo que permite que múltiples objetos tengan la oportunidad de procesar solicitudes
  • Patrón de estado: permite que un objeto cambie su comportamiento cuando cambia su estado interno
  • Visitor Pattern: Agregue nuevas operaciones sin cambiar la estructura de datos, es decir, separe el procesamiento de la estructura de datos

Los siete patrones de diseño más utilizados son los siguientes:

  1. Patrón único
  2. Patrón de fábrica
  3. Patrón de observador
  4. Patrón de estrategia
  5. Patrón de adaptador
  6. Patrón decorador
  7. Patrón de comando

2. Siete principios del diseño de software

Los Siete Principios del Diseño de Software, también conocidos como los Siete Principios SOLID原则del Diseño de Software, es un conjunto de principios rectores para el diseño orientado a objetos diseñado para ayudar a los desarrolladores a escribir código mantenible, extensible y comprensible. 这些原则和设计模式Estrechamente relacionados, juntos proporcionan un conjunto completo de pautas para la programación orientada a objetos. SOLID 是一组面向对象编程和设计原则的首字母缩略词, la primera letra de los primeros cinco principios de diseño enumerados a continuación

Aquí hay una breve introducción a los principios SOLID y su relación con los patrones de diseño:

  1. Principio de responsabilidad única (Single Responsibility Principle) :
    una clase debe tener una sola causa de cambio. Esto significa uno 个类应该只负责一项职责. Seguir el principio de responsabilidad única puede mejorar la clase内聚性和可维护性

    Patrones de diseño relacional: 单例模式、工厂模式、观察者模式etc. Todos estos patrones de diseño ayudan a implementar el principio de responsabilidad única y dividen diferentes funciones en diferentes clases.

  2. Principio abierto/cerrado :
    las entidades de software (clases, módulos, funciones, etc.) deben 对扩展开放,对修改封闭. Esto significa que la nueva funcionalidad debe introducirse extendiendo el código existente en lugar de modificar directamente el código existente.

    Patrones de diseño relacional: 策略模式、装饰器模式、观察者模式etc. Estos patrones de diseño respaldan el principio de abierto y cerrado, y logran la extensibilidad definiendo interfaces, clases abstractas y combinaciones.

  3. Principio de sustitución de Liskov (Principio de sustitución de Liskov) :
    子类对象应该能够替换其基类对象,而不影响程序的正确性. Es decir, sin cambiar la corrección del programa, la clase derivada puede extender las funciones de la clase base

    Patrones de diseño relacional: 工厂模式、模板方法模式etc. Estos patrones de diseño utilizan las características de las subclases para reemplazar las clases base, lo que hace que el código sea más flexible y extensible.

  4. Principio de segregación de interfaces :
    no se debe obligar a los clientes a depender de interfaces que no utilizan. Una clase no debe depender de interfaces que no necesita

    Patrones de diseño relacional: 适配器模式、策略模式etc. Estos patrones de diseño ayudan a implementar el principio de aislamiento de la interfaz, dividen las interfaces grandes en varias interfaces pequeñas y permiten que las clases solo dependan de las interfaces requeridas.

  5. Principio de inversión de dependencia (Principio de inversión de dependencia) :
    Módulos de alto nivel 不应该依赖于低层模块,而是应该依赖于抽象. Las abstracciones no deben depender de detalles de implementación concretos, pero las implementaciones concretas deben depender de abstracciones

    Patrones de diseño relacional: 依赖注入、工厂模式etc. Estos patrones de diseño siguen el principio de inversión de dependencia y reducen el acoplamiento entre módulos basándose en abstracciones en lugar de implementaciones concretas.

  6. Principio de reutilización de composición/agregación :
    uso prioritario 对象组合或聚合,而不是继承来达到代码复用的目的. A través de las relaciones de composición, los componentes se pueden agregar, quitar o reemplazar de manera más flexible

    Patrones de diseño relacional: 装饰器模式、组合模式etc. Estos patrones de diseño enfatizan la composición o agregación de objetos en lugar de la herencia para la reutilización del código.

  7. Ley de Deméter (Ley de Deméter, Principio del Mínimo Conocimiento) :
    Un objeto debe saber lo menos posible sobre otros objetos. Ahora mismo一个类应该尽量减少与其他类之间的交互,尽量降低耦合性

    Patrones de diseño relacional: 外观模式、中介者模式etc., estos patrones de diseño ayudan a reducir la interacción directa entre objetos y reducen el acoplamiento entre clases mediante la introducción de clases intermedias.

El propósito de los principios de diseño de software:

Reduzca el acoplamiento y la complejidad entre objetos, mejore la cohesión de los objetos y aumente la reutilización, escalabilidad y mantenibilidad de los programas.

3. Patrón de diseño detallado

1. Patrón único

Singleton Pattern (Patrón Singleton) es un patrón de diseño creacional, es 确保一个类只有一个实例,并提供一个全局访问点来获取该实例. esto está bien避免多次实例化相同类的对象,节省内存资源,并确保在整个应用程序中只有一个共享的实例被使用

introducción detallada

En el patrón singleton, hay varios puntos importantes a considerar:

  1. Constructor privado: para evitar la instanciación directa de objetos en clases externas, el constructor de una clase singleton debe configurarse como privado, de modo que otras clases no puedan newcrear objetos de esta clase a través del operador.

  2. Variables miembro estáticas: las clases Singleton necesitan una variable miembro estática para mantener una referencia a la única instancia para garantizar la exclusividad global

  3. Método getter estático: una clase singleton debe proporcionar un método público estático para obtener la única instancia de la clase. Este método suele denominarsegetInstance()

  4. Inicialización diferida:getInstance() la instancia se crea cuando se llama al método por primera vez , en lugar de cuando se carga la clase, por lo que se puede lograr la inicialización diferida y mejorar el rendimiento.

  5. seguridad del hilo: 需要考虑多线程环境下的并发访问问题。可以使用同步机制来保证线程安全,但需要注意性能开销

ejemplo de código

package com.zhouquan.entity;

/**
 * @author ZhouQuan
 * @description 单例模式
 * @date 2023-07-23 09:57
 **/
public class Singleton {
    
    

    /**
     * 私有的静态成员变量,用于保存唯一实例的引用
     */
    private static Singleton instance;

    /**
     * 私有的构造函数,防止外部类实例化
     */
    private Singleton() {
    
    
    }

    /**
     * 静态的获取实例方法
     *
     * @return
     */
    public static synchronized Singleton getInstance() {
    
    
        //  延迟初始化,在首次调用该方法时才创建实例
        if (instance == null) {
    
    
            instance = new Singleton();
        }
        return instance;
    }

    /**
     * 其他业务方法
     */
    public void doSomething() {
    
    
        System.out.println("其他业务方法...");
    }

    public static void main(String[] args) {
    
    
        // 使用单例模式获取实例
        Singleton singleton1 = Singleton.getInstance();
        Singleton singleton2 = Singleton.getInstance();

        // 验证是否是同一个实例
        if (singleton1 == singleton2) {
    
    
            System.out.println("相同的实例对象");
        } else {
    
    
            System.out.println("不同的实例对象");
        }
    }
}

En el ejemplo anterior, Singletonel constructor de la clase es privado, lo que garantiza que otras clases no puedan instanciar la clase directamente. Obtenga la única instancia a través getInstance()del método, usando un simple 同步机制来保证线程安全. 这种简单的同步机制虽然保证了线程安全,但在多线程环境下可能会有一些性能开销Tenga en cuenta que En el desarrollo real, puede considerar usar una implementación más eficiente, como el modo singleton basado en clases internas estáticas

Ejecute el código anterior y verá que el resultado muestra eso singleton1y singleton2son la misma instancia, lo que demuestra que el patrón singleton garantiza que la clase tiene solo una instancia única

Escenas a utilizar

El siguiente es el escenario de uso del modo singleton, leyendo dos ajustes en la configuración del sistema. Una vez que se inicia el proyecto, la configuración del sistema se obtiene llamando al método de instancia get, de modo que la misma configuración se puede leer en cualquier parte del proyecto.
Lo que necesita saber es que cuando use esta configuración, obtenga la información de configuración del proyecto a través de SystemConfig.getInstance() en lugar de agregar la anotación @configuration a la clase para obtener la instancia de configuración, lo que puede mejorar la velocidad de inicio del proyecto.

package com.zhouquan.entity;

import lombok.Data;

/**
 * @author ZhouQuan
 * @desciption 单例模式的使用场景
 * @date 2023/7/23 10:17
 */
@Data
public class SystemConfig {
    
    

    private static SystemConfig instance = null;

    /**
     * 是否启动定时
     */
    private boolean enableTime;

    /**
     * 是否重试数据同步
     */
    private boolean retrySync;

    private SystemConfig() {
    
    
    }

    public static SystemConfig getInstance() {
    
    
        if (instance == null) {
    
    
            instance = new SystemConfig();
        }
        return instance;
    }
}

Ventajas y desventajas del modo singleton

ventaja:

  1. 唯一实例: el modo singleton garantiza que solo exista una instancia de una clase, lo que puede evitar instancias múltiples, evitar el desperdicio de recursos y también garantizar la unicidad del objeto, lo cual es conveniente para el acceso global a la instancia

  2. 全局访问: dado que la instancia del patrón singleton es accesible globalmente a través de la aplicación, se puede compartir entre diferentes módulos y componentes para facilitar el intercambio de datos y la comunicación

  3. 延迟实例化: El modo singleton puede implementar la creación de instancias diferidas, es decir, crear una instancia solo cuando sea necesario. Esto puede ahorrar recursos del sistema y mejorar la eficiencia de inicio del sistema en algunos casos.

  4. 避免竞态条件: En un entorno de subprocesos múltiples, el modo singleton puede evitar la condición de carrera (condición de carrera) causada por varios subprocesos que crean instancias al mismo tiempo y garantizar la exclusividad y corrección de la instancia.

defecto:

  1. Difícil de extender: dado que el patrón singleton restringe la clase para que solo tenga una instancia, puede encontrar algunas dificultades al extenderse. Si necesita extender la clase singleton, es posible que deba modificar el código original

  2. Problema del principio de responsabilidad única: el patrón singleton mezcla la lógica de creación de la instancia y la responsabilidad de la instancia, lo que puede violar el principio de responsabilidad única. Esto hará que el código de la clase singleton sea más complicado.

  3. Problemas del ciclo de vida de los objetos: dado que existen instancias del patrón singleton a lo largo del ciclo de vida de la aplicación, puede hacer que los objetos residan en la memoria durante mucho tiempo, lo que aumenta el uso de la memoria.

  4. Problemas de capacidad de prueba: dado que el patrón singleton accede a la instancia globalmente, puede dificultar la prueba unitaria de las clases que dependen de instancias singleton

En general, el patrón singleton es muy útil en algunas situaciones, especialmente en aquellas que necesitan garantizar una instancia única a nivel mundial y evitar el desperdicio de recursos. Sin embargo, se requiere una consideración cuidadosa al usar el patrón singleton para garantizar que no aumente la complejidad del código y no afecte la escalabilidad y la capacidad de prueba del sistema.

2. Patrón de fábrica

Factory Pattern (Patrón de fábrica) es un patrón de diseño de creación que proporciona una interfaz unificada para crear objetos sin exponer la lógica de creación de objetos. Usando el patrón de fábrica, puede将对象的实例化过程封装在工厂类中,客户端只需要与工厂类进行交互,从而降低了代码的耦合性,增强了代码的可维护性和可扩展性

Hay tres variantes comunes del patrón de fábrica: patrón de fábrica simple, patrón de método de fábrica y patrón de fábrica abstracto.

ilustrar

  • Product es una interfaz de producto, que define el comportamiento general show() de los objetos de producto

  • ProductoConcretoA y ProductoConcretoB son respectivamente el producto específico A y el producto específico B. Implementan la interfaz del Producto y proporcionan su propia implementación específica

  • SimpleFactory es una clase de fábrica simple que contiene el método estático createProduct() para crear instancias de productos específicos de acuerdo con diferentes parámetros.

  • Main es el código del cliente, que obtiene la instancia del producto llamando al método estático de SimpleFactory y usa el método show() del producto.

	                       +----------------------+
	                       |       Product        |
	                       +----------------------+
	                       |      <<interface>>   |
	                       |      show()          |
	                       +----------------------+
	                                 ^
	                                 |
	                                 |
	                                 |
	    	+--------------------------+ +----------------------------+
	    	|                            |                        	  |
	+-----------------+         +----------------+       +----------------+
    |ConcreteProductA |         | SimpleFactory  |       |ConcreteProductB|
    +-----------------+         +----------------+       +----------------+
    |     show()      |         | createProduct()|       |     show()     |
	+----------------+          +----------------+       +----------------+
	                                      ^
	                                      |
	                                      |
	                                      |
	                                      |
	                               +------------------+
	                               | ConcreteProductA |
	                               +------------------+
	                               |      show()      |
	                               +------------------+

2.1 Patrón de fábrica simple

El patrón de fábrica simple no es un patrón de diseño estándar, es más como un hábito de programación. En el patrón de fábrica simple, creamos una clase de fábrica que crea diferentes instancias de clases de productos de acuerdo con diferentes parámetros.

Ejemplo de código:

package com.zhouquan.entity.factory;

/**
 * 产品接口
 */
interface Product {
    
    
    /**
     * 商品类需要实现的方法
     */
    void show();
}

/**
 * 具体产品A
 */
class ConcreteProductA implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("具体产品A");
    }
}

/**
 * 具体产品B
 */
class ConcreteProductB implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("具体产品B");
    }
}

/**
 * 产品枚举类
 */
enum ProductEnums {
    
    
    /**
     * 产品A
     */
    CONCRETE_PRODUCT_A,

    /**
     * 产品B
     */
    CONCRETE_PRODUCT_B
}

/**
 * 简单工厂类
 */
class SimpleFactory {
    
    
    public static Product createProduct(ProductEnums productEnums) {
    
    
        if (productEnums.equals(ProductEnums.CONCRETE_PRODUCT_A)) {
    
    
            return new ConcreteProductA();
        } else if (productEnums.equals(ProductEnums.CONCRETE_PRODUCT_B)) {
    
    
            return new ConcreteProductB();
        } else {
    
    
            throw new IllegalArgumentException("无效产品类型");
        }
    }
}

/**
 * @author ZhouQuan
 * @description 简单工厂模式(Simple Factory Pattern)
 * @date 2023-07-23 10:36
 **/
public class SimpleFactoryPattern {
    
    
    public static void main(String[] args) {
    
    
        Product productA = SimpleFactory.createProduct(ProductEnums.CONCRETE_PRODUCT_A);
        Product productB = SimpleFactory.createProduct(ProductEnums.CONCRETE_PRODUCT_B);

        productA.show();
        productB.show();
    }
}

2.2 Patrón de método de fábrica (Patrón de método de fábrica)

El patrón del método de fábrica delega la lógica de creación de cada producto concreto a su respectiva clase de fábrica. Cada producto específico corresponde a una clase de fábrica, y los productos específicos se crean implementando la interfaz de fábrica.

Ejemplo de código:

package com.zhouquan.entity.factory;

/**
 * 产品接口
 */
interface Product {
    
    
    /**
     * 商品类需要实现的方法
     */
    void show();
}

/**
 * 具体产品A
 */
class ConcreteProductA implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("具体产品A");
    }
}

/**
 * 具体产品B
 */
class ConcreteProductB implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("具体产品B");
    }
}

/**
 * 工厂接口
 */
interface Factory {
    
    
    Product createProduct();
}

/**
 * 具体工厂A
 */
class ConcreteFactoryA implements Factory {
    
    
    @Override
    public Product createProduct() {
    
    
        return new ConcreteProductA();
    }
}

/**
 * 具体工厂B
 */
class ConcreteFactoryB implements Factory {
    
    
    @Override
    public Product createProduct() {
    
    
        return new ConcreteProductB();
    }
}

/**
 * @author ZhouQuan
 * @desciption 工厂方法模式(Factory Method Pattern)
 * @date 2023/7/23 11:35
 */
public class FactoryMethodPattern {
    
    
    public static void main(String[] args) {
    
    
        Factory factoryA = new ConcreteFactoryA();
        Factory factoryB = new ConcreteFactoryB();

        Product productA = factoryA.createProduct();
        Product productB = factoryB.createProduct();

        productA.show();
        productB.show();
    }
}

2.3 Patrón de fábrica abstracto

El patrón de fábrica abstracto proporciona una interfaz para crear una serie de objetos de productos relacionados o interdependientes. Cada fábrica de hormigón implementa esta interfaz para crear un conjunto de objetos de productos.

Ejemplo de código:

package com.zhouquan.entity.factory;

/**
 * 产品接口
 */
interface Product {
    
    
    /**
     * 商品类需要实现的方法
     */
    void show();
}

/**
 * 具体产品A
 */
class ConcreteProductA implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("具体产品A");
    }
}

/**
 * 具体产品B
 */
class ConcreteProductB implements Product {
    
    
    @Override
    public void show() {
    
    
        System.out.println("具体产品B");
    }
}

/**
 * 工厂接口
 */
interface Factory {
    
    
    Product createProduct();
}

/**
 * 具体工厂A
 */
class ConcreteFactoryA implements Factory {
    
    
    @Override
    public Product createProduct() {
    
    
        return new ConcreteProductA();
    }
}

/**
 * 具体工厂B
 */
class ConcreteFactoryB implements Factory {
    
    
    @Override
    public Product createProduct() {
    
    
        return new ConcreteProductB();
    }
}

/**
 * @author ZhouQuan
 * @desciption 工厂方法模式(Factory Method Pattern)
 * @date 2023/7/23 11:35
 */
public class FactoryMethodPattern {
    
    
    public static void main(String[] args) {
    
    
        Factory factoryA = new ConcreteFactoryA();
        Factory factoryB = new ConcreteFactoryB();

        Product productA = factoryA.createProduct();
        Product productB = factoryB.createProduct();

        productA.show();
        productB.show();
    }
}

3. Patrón de observador (Patrón de observador)

El patrón de observador (Observer Pattern) es un tipo de 行为型设计模式, que se usa para definir一对多的依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都能够得到通知并自动更新

El papel principal del modo observador.

  1. Sujeto (sujeto): también conocido como 被观察者或可观察者, es un objeto con un estado, cuando cambie su estado, avisará a todos los observadores registrados

  2. Observer (observador): El observador presta atención al cambio de estado del tema, y ​​cuando el tema cambia, recibe la notificación y realiza la operación de actualización correspondiente

La ventaja del patrón Observer es 解耦了主题和观察者que les permite variar independientemente unos de otros, al mismo tiempo que permite增加了系统的灵活性和扩展性

Elementos del patrón de observador

  1. Interfaz de sujeto (asunto): define métodos para agregar, eliminar y notificar observadores

  2. Clase ConcreteSubject (sujeto específico): implementa la interfaz Sujeto, mantiene la lista de observadores y notifica al observador cuando cambia el estado

  3. Interfaz de observador (observador): define el método para recibir notificaciones y realizar las actualizaciones correspondientes

  4. Clase ConcreteObserver (observador específico): implementa la interfaz Observer y realiza las operaciones correspondientes al recibir notificaciones de temas

ejemplo de código

package com.zhouquan.entity.observer;

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


/**
 * 主题接口
 */
interface Subject {
    
    
    /**
     * 注册观察者
     */
    void registerObserver(Observer observer);

    /**
     * 移除观察者
     */
    void removeObserver(Observer observer);

    /**
     * 通知所有已注册的观察者
     */
    void notifyObservers();

}

/**
 * 具体主题类
 * 负责维护观察者列表和状态,并在状态发生变化时通知所有注册的观察者
 */
class ConcreteSubject implements Subject {
    
    
    /**
     * 观察者对象列表
     */
    private List<Observer> observers = new ArrayList<>();

    /**
     * 观察者状态
     */
    private String state;

    @Override
    public void registerObserver(Observer observer) {
    
    
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
    
    
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
    
    
        for (Observer observer : observers) {
    
    
            observer.update(state);
        }
    }

    /**
     * 设置状态,并通知观察者
     *
     * @param state
     */
    public void setState(String state) {
    
    
        this.state = state;
        notifyObservers();
    }
}

/**
 * 观察者接口
 */
interface Observer {
    
    
    void update(String state);
}

/**
 * 具体观察者类
 * 实现了Observer接口,在接收到主题通知时执行相应的操作
 */
class ConcreteObserver implements Observer {
    
    
    private String name;

    public ConcreteObserver(String name) {
    
    
        this.name = name;
    }

    @Override
    public void update(String state) {
    
    
        System.out.println(name + "收到更新,新状态为:" + state);
    }
}

/**
 * @author ZhouQuan
 * @description 观察者模式
 * @date 2023-07-23 21:00
 **/
public class ObserverPattern {
    
    
    public static void main(String[] args) {
    
    
        ConcreteSubject subject = new ConcreteSubject();

        Observer observer1 = new ConcreteObserver("Observer1");
        Observer observer2 = new ConcreteObserver("Observer2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.setState("State 1");

        subject.removeObserver(observer1);

        subject.setState("State 2");
    }
}

subjectUn objeto de sujeto concreto y dos objetos de observador concretos observer1se crean en el código del método principal observer2. Primero, registre dos observadores en el tema, y ​​luego setState()cambie el estado del tema a través del método, y los observadores serán notificados y actualizados. Luego, elimine un observador del sujeto, cambie el estado del sujeto nuevamente y solo se notificará a un observador.
De esta forma, el patrón del observador implementa con éxito 一对多la relación de dependencia. Cuando el estado del sujeto cambia, todos los observadores pueden ser notificados y actualizados en consecuencia.

4. Patrón de estrategia

El patrón de estrategia es un tipo 行为型设计模式que define una familia de algoritmos y encapsula cada algoritmo para que puedan reemplazarse entre sí, de modo que客户端代码与具体算法的实现解耦

El propósito principal del patrón de estrategia es permitir 算法的变化独立于使用算法的客户端. De esta forma, el código cliente puede elegir diferentes algoritmos según las necesidades sin modificar su código, realizando así el algoritmo动态切换

El papel principal de la estructura central del patrón de estrategia.

  1. Contexto (entorno): la clase de entorno se utiliza para contener un objeto de política y llamar al método del objeto de política cuando sea necesario. Suele representar al cliente utilizando el接口

  2. Estrategia (estrategia): Interfaz de estrategia, definida 算法的公共接口. La clase de estrategia concreta implementa la interfaz de estrategia, proporcionada 不同的算法实现.

  3. ConcreteStrategy (estrategia concreta): 具体策略类, que implementa el algoritmo definido por la interfaz de estrategia. Cuando el cliente elige una estrategia diferente, use una clase de estrategia concreta diferente

					    +-------------------+
					    |     Strategy      |
					    +-------------------+
					    | + doOperation()   |
					    +-------------------+
					             ^
					             |
					             | implements
					             |
	+------------------------+       +------------------------+
	|   ConcreteStrategyA    |       |   ConcreteStrategyB    |
	+------------------------+       +------------------------+
	| + doOperation()        |       | + doOperation()       |
	+------------------------+       +------------------------+
					             ^
					             |
					             | uses
					             |
					        +------------+
					        |  Context   |
					        +------------+
					        | - strategy |
					        +------------+
					             ^
					             |
					             | depends on
					             |
					        +--------------+
					        |   Main       |
					        +--------------+

Ventajas del patrón de estrategia

La ventaja del patrón de estrategia es que puede有效地避免使用大量的条件判断语句,将算法的选择和使用与客户端的代码解耦,提高代码的灵活性和可维护性

Ejemplo de patrón de estrategia de código

package com.zhouquan.entity.strategy;

/**
 * IP策略接口
 */
interface IpStrategy {
    
    
    /**
     * 校验ip类型
     * 判断是IPv4还是IPv6
     *
     * @param ip ip字符串
     * @return string 返回校验结果
     */
    String checkIpType(String ip);
}

/**
 * 具体策略 IPv4
 */
class IPv4Strategy implements IpStrategy {
    
    
    @Override
    public String checkIpType(String ip) {
    
    
        return "使用IPv4策略,结果为:" + ip;
    }
}

/**
 * 具体策略 IPv6
 */
class IPv6Strategy implements IpStrategy {
    
    
    @Override
    public String checkIpType(String ip) {
    
    
        return "使用IPv6策略,结果为:" + ip;
    }
}

/**
 * 环境类
 */
class IpContext {
    
    
    private IpStrategy ipStrategy;

    public IpContext(IpStrategy ipStrategy) {
    
    
        this.ipStrategy = ipStrategy;
    }

    public String checkIpType(String ipAddress) {
    
    
        return ipStrategy.checkIpType(ipAddress);
    }
}

/**
 * @author ZhouQuan
 * @description 策略模式(Strategy Pattern)
 * @date 2023-07-23 21:27
 **/
public class StrategyPattern {
    
    
    public static void main(String[] args) {
    
    
        String ipv4Address = "192.168.1.1";
        String ipv6Address = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";

        /**
         * 策略模式的主要目的是让算法的变化独立于使用算法的代码
         * 通过实例化不同的`Context`对象,并传入不同的具体策略类可以根据需要选择不同的算法,而不
         * 需要修改其代码,从而实现了算法的动态切换
         */
        IpContext ipv4Context = new IpContext(new IPv4Strategy());
        IpContext ipv6Context = new IpContext(new IPv6Strategy());

        String ipv4Result = ipv4Context.checkIpType(ipv4Address);
        String ipv6Result = ipv6Context.checkIpType(ipv6Address);

        System.out.println("IPv4 地址校验:" + ipv4Result);
        System.out.println("IPv6 地址校验:" + ipv6Result);
    }
}

En el ejemplo anterior, creamos una interfaz de política IpStrategye implementamos dos clases de política específicas IPv4Strategyy IPv6Strategyrespectivamente ejecutan diferentes algoritmos para verificar que la IpContextclase de tipo ip es una clase de entorno, mantener un objeto de política y llamar a la política cuando sea necesario método de objeto

5. Patrón de adaptador

El patrón de adaptador (Adapter Pattern) es una clase 结构型设计模式que permite convertir la interfaz de una clase en otra interfaz que el cliente espera, de modo que las clases originalmente incompatibles puedan trabajar juntas. El patrón adaptador se utiliza principalmente para解决现有系统之间接口不兼容的问题,同时也能够将已有类和新类进行协调工作

El papel principal del patrón adaptador.

  1. Interfaz de destino (Target): la interfaz esperada por el cliente, que定义了客户端可以调用的方法

  2. Adaptador: 适配器是将原有接口转换成目标接口的中间桥梁. implementa la interfaz de destino, y持有原有接口的引用,将客户端请求转发给原有接口

  3. Adaptado: El adaptado es una clase existente cuya interfaz no es compatible con la interfaz de destino esperada por el cliente

La ventaja del patrón Adapter es que puede使不兼容的类能够协调工作,同时也提高了代码的复用性和灵活性

Ejemplo de código de patrón de adaptador

package com.zhouquan.entity.adapter;

/**
 * 目标接口
 */
interface MediaPlayer {
    
    
    /**
     * 视频播放方法
     *
     * @param audioType 视频类型
     * @param fileName  文件名
     */
    void play(AudioType audioType, String fileName);
}

/**
 * 视频类型的枚举类
 */
enum AudioType {
    
    
    MP4,
    VLC
}

/**
 * 被适配者:AdvancedMediaPlayer接口
 */
interface AdvancedMediaPlayer {
    
    

    /**
     * vlc格式播放
     *
     * @param fileName
     */
    void playVlc(String fileName);

    /**
     * mp4格式播放
     *
     * @param fileName
     */
    void playMp4(String fileName);
}

/**
 * 具体被适配者:VlcPlayer类
 */
class VlcPlayer implements AdvancedMediaPlayer {
    
    
    @Override
    public void playVlc(String fileName) {
    
    
        System.out.println("播放vlc格式.文件名: " + fileName);
    }

    @Override
    public void playMp4(String fileName) {
    
    
        // 空实现,不处理
    }
}

/**
 * 具体被适配者:Mp4Player类
 */
class Mp4Player implements AdvancedMediaPlayer {
    
    
    @Override
    public void playVlc(String fileName) {
    
    
        // 空实现,不处理
    }

    @Override
    public void playMp4(String fileName) {
    
    
        System.out.println("播放mp4格式.文件名: " + fileName);
    }
}

/**
 * 适配器类:MediaPlayerAdapter
 */
class MediaPlayerAdapter implements MediaPlayer {
    
    
    private AdvancedMediaPlayer advancedMediaPlayer;

    public MediaPlayerAdapter(AudioType audioType) {
    
    
        if (audioType == AudioType.VLC) {
    
    
            advancedMediaPlayer = new VlcPlayer();
        } else if (audioType == AudioType.MP4) {
    
    
            advancedMediaPlayer = new Mp4Player();
        }
    }

    @Override
    public void play(AudioType audioType, String fileName) {
    
    
        if (audioType == AudioType.VLC) {
    
    
            advancedMediaPlayer.playVlc(fileName);
        } else if (audioType == AudioType.MP4) {
    
    
            advancedMediaPlayer.playMp4(fileName);
        }
    }
}

/**
 * @author ZhouQuan
 * @description 适配器模式(Adapter Pattern)
 * @date 2023-07-23 22:03
 **/
public class AdapterPattern {
    
    
    public static void main(String[] args) {
    
    
        MediaPlayer mediaPlayer = new MediaPlayerAdapter(AudioType.MP4);
        mediaPlayer.play(AudioType.MP4, "蔡徐坤打篮球.mp4");
    }
}

En el ejemplo anterior se implementa un patrón de adaptador simple. MediaPlayeres la interfaz de destino y AdvancedMediaPlayeres una interfaz incompatible existente. VlcPlayery Mp4Playerson los adaptados concretos. MediaPlayerAdapterEs la clase de adaptador, que implementa la interfaz de destino y contiene una AdvancedMediaPlayerreferencia para reenviar la solicitud del cliente al adaptador específico.

6. Patrón de decorador (Patrón de decorador)

El patrón Decorator (Patrón Decorator) es un 结构型设计模式, 允许你在不改变对象接口的情况下,动态地添加功能到对象上. Agrega un nuevo comportamiento al objeto original mediante la creación de una clase de decorador para envolver el objeto original. Esto hace que el código sea más flexible mientras se ajusta a开放封闭原则(Open/Closed Principle),即对扩展开放,对修改关闭

El papel principal del patrón decorador.

  1. Componente (componente abstracto): define una interfaz abstracta, que puede ser una interfaz o una clase abstracta, y tanto el objeto decorado como el decorador implementan esta interfaz.

  2. ConcreteComponent (componente concreto): implementa la interfaz del componente abstracto y es el objeto original que se decorará

  3. Decorador (decorador): también una clase o interfaz abstracta, contiene una referencia a un componente abstracto y define una interfaz consistente con el componente abstracto.

  4. ConcreteDecorator (decorador concreto): hereda de la clase decorador, implementa la interfaz decorador y es responsable de agregar nuevas funciones a componentes específicos

ejemplo de código

A continuación, se utiliza un ejemplo simple de Java para ilustrar el uso del patrón decorador. Tome una cafetería como ejemplo, hay diferentes tipos de café (componentes de concreto) y se pueden agregar condimentos adicionales al café (decoradores de concreto)

package com.zhouquan.entity.decorator;


/**
 * Component(抽象构件)
 */
interface Coffee {
    
    
    double getCost();

    String getDescription();
}

/**
 * ConcreteComponent(具体构件)
 */
class SimpleCoffee implements Coffee {
    
    
    @Override
    public double getCost() {
    
    
        return 10.0;
    }

    @Override
    public String getDescription() {
    
    
        return "一杯原始咖啡 ";
    }
}

/**
 * Decorator(装饰器)
 */
abstract class CoffeeDecorator implements Coffee {
    
    
    protected Coffee coffee;

    public CoffeeDecorator(Coffee coffee) {
    
    
        this.coffee = coffee;
    }
}

/**
 * ConcreteDecorator(具体装饰器)
 */
class MilkDecorator extends CoffeeDecorator {
    
    
    public MilkDecorator(Coffee coffee) {
    
    
        super(coffee);
    }

    @Override
    public double getCost() {
    
    
        return coffee.getCost() + 5.0;
    }

    @Override
    public String getDescription() {
    
    
        return coffee.getDescription() + ",加牛奶 ";
    }
}

/**
 * ConcreteDecorator(具体装饰器)
 */
class SugarDecorator extends CoffeeDecorator {
    
    
    public SugarDecorator(Coffee coffee) {
    
    
        super(coffee);
    }

    @Override
    public double getCost() {
    
    
        return coffee.getCost() + 2.0;
    }

    @Override
    public String getDescription() {
    
    
        return coffee.getDescription() + ",加糖 ";
    }
}

/**
 * @author ZhouQuan
 * @description 装饰器模式(Decorator Pattern)
 * @date 2023-07-23 22:33
 **/
public class DecoratorPattern {
    
    
    public static void main(String[] args) {
    
    
        // 原始咖啡
        Coffee simpleCoffee = new SimpleCoffee();
        // 一杯原始咖啡 10.0
        System.out.println(simpleCoffee.getDescription() + simpleCoffee.getCost());

        // 使用装饰器添加调料
        Coffee milkCoffee = new MilkDecorator(simpleCoffee);
        Coffee sugarMilkCoffee = new SugarDecorator(milkCoffee);
        //一杯原始咖啡 ,加牛奶 ,加糖 17.0
        System.out.println(sugarMilkCoffee.getDescription() + sugarMilkCoffee.getCost());
    }
}

El patrón decorador facilita agregar diferentes especias al café sin modificar la clase de café original. Esto hace que el código sea más flexible y puede agregar fácilmente nuevas clases de decorador para ampliar la funcionalidad.

7. Patrón de comando

El patrón de comando es una 行为型设计模式forma de encapsular una solicitud (comando) en un objeto, lo que le permite parametrizar otros objetos con diferentes solicitudes, colas o registros. Puede desacoplar el remitente (Invoker) y el receptor (Receiver) de la solicitud, de modo que el remitente no necesita conocer el proceso de procesamiento específico del receptor, sino que solo necesita ejecutar la solicitud a través del objeto de comando.

El papel principal del modo de comando.

  1. Comando: una interfaz que declara que se realizará una acción, que generalmente contiene un solo executemétodo.

  2. ConcreteCommand (comando específico): implementa la interfaz Command, executeencapsula operaciones específicas en el método y mantiene un objeto receptor al mismo tiempo.

  3. Receptor (Receiver): Encargado de realizar operaciones específicas.

  4. Invoker (caller): Encargado de invocar executeel método del objeto comando para ejecutar la petición.

ejemplo de código

Supongamos que tenemos un control remoto con algunos botones, cada botón puede controlar diferentes equipos eléctricos (como luces, estéreos, etc.)

package com.zhouquan;

/**
 * Command(命令)
 */
interface Command {
    
    
    void execute();
}

/**
 * ConcreteCommand(具体命令) - 电灯开启命令
 */
class LightOnCommand implements Command {
    
    
    private Light light;

    public LightOnCommand(Light light) {
    
    
        this.light = light;
    }

    @Override
    public void execute() {
    
    
        light.turnOn();
    }
}

/**
 * ConcreteCommand(具体命令) - 电灯关闭命令
 */
class LightOffCommand implements Command {
    
    
    private Light light;

    public LightOffCommand(Light light) {
    
    
        this.light = light;
    }

    @Override
    public void execute() {
    
    
        light.turnOff();
    }
}

/**
 * Receiver(接收者) - 电灯
 */
class Light {
    
    
    public void turnOn() {
    
    
        System.out.println("开灯");
    }

    public void turnOff() {
    
    
        System.out.println("关灯");
    }
}

/**
 * Invoker(调用者) - 遥控器
 */
class RemoteControl {
    
    
    private Command command;

    public void setCommand(Command command) {
    
    
        this.command = command;
    }

    public void pressButton() {
    
    
        command.execute();
    }
}

/**
 * @author ZhouQuan
 * @description 命令模式(Command Pattern)
 * @date 2023-07-23 22:45
 **/
public class CommandPattern {
    
    
    public static void main(String[] args) {
    
    
        RemoteControl remoteControl = new RemoteControl();

        Light light = new Light();
        Command lightOnCommand = new LightOnCommand(light);
        Command lightOffCommand = new LightOffCommand(light);

        remoteControl.setCommand(lightOnCommand);
        remoteControl.pressButton();

        remoteControl.setCommand(lightOffCommand);
        remoteControl.pressButton();
    }
}


La solicitud (controlar la luz) se encapsula en un objeto de comando específico a través del modo de comando, que desacopla el emisor (control remoto) y el receptor (luz), logrando así un método de control más flexible y escalable.

Supongo que te gusta

Origin blog.csdn.net/qq_29864051/article/details/131875921
Recomendado
Clasificación