I. Introducción
Recientemente, en la transformación de algunos códigos históricos, encontré un rasgo muy obvio, la mayoría de los códigos son narrativas, y las historias se explican de manera sencilla según el proceso de desarrollo del evento.
La ventaja de este método es que está más en línea con los hábitos de pensamiento humano. Al final se describe una línea principal. El código no es demasiado difícil de leer. Mientras sigas la vid, puedes sentir el melón, pero la desventaja también es obvia. Una vez que necesites insertar algunas historias nuevas en la línea de la historia Elementos como: agregar un nuevo personaje, una nueva línea de tiempo requerirán muchos cambios en la línea de la historia para que coincida con la integración de este nuevo elemento, e incluso tendrán un efecto destructivo en el artículo original.
Para resolver este problema, la gente ha resumido muchos tipos de estructuras de artículos, tales como: estructura de puntos totales, estructura de lado a lado, estructura de puntos totales de total, etc. Con estas estructuras, al agregar nuevos elementos, ni siquiera es necesario considerar nuevos elementos. Para conocer la relevancia de la historia original, simplemente extraiga una historia ramificada y cuéntela de forma independiente, siempre que pueda converger con la historia principal antes del final de la historia general (¿es muy similar a git?).
En el campo del desarrollo de software, existen muchos resúmenes de prácticas muy útiles, que llamamos patrones de diseño. Nadie desconoce los patrones de diseño. Se estima que cualquiera que lo encuentre podrá distinguir N patrones de diseño, pero además de los conceptos de estos patrones de diseño, muchas personas no saben cómo utilizar estos patrones de diseño de manera flexible. Así que tome este artículo para aprender la idea de patrones de diseño con todos.
Dos comprenden los patrones de diseño
Intento usar los ejemplos y el lenguaje más fáciles de entender para describir los patrones de diseño que entiendo, con la esperanza de ayudar a todos.
Además, no es necesario ser competente en todos los patrones de diseño, siempre que pueda integrar patrones de diseño comunes, puede hacer que su código sea elegante. Al igual que Cheng Yaojin solo sabe cómo hacer tres golpes, pero su habilidad es incomparable y aún puede viajar por el mundo.
1 Modo de fábrica (Factory)
Fábrica simple
Cuando Xiao Ming persiguió a su hermana, la invitó a tomar mucho café. Le encanta beber capuchino. Cada vez que va a una cafetería, solo necesita decirle al camarero "una taza de capuchino", aunque los gustos de cada familia son diferentes. Pero ya sea Star Papa o Costa, pueden proporcionar capuchino. Papa Star y Costa aquí son fábricas que producen café.
(1) Estructura de modelo de fábrica simple
El patrón de fábrica simple incluye los siguientes roles:
Fábrica: rol de fábrica responsable de implementar la lógica interna de creación de todas las instancias.
Producto: Función de producto abstracto: es la clase principal de todos los objetos creados, responsable de describir la interfaz común compartida por todas las instancias.
ConcreteProduct: función de producto específico: es el objetivo de creación, todos los objetos creados actúan como instancias de una clase específica de esta función.
Diagrama de estructura:
Diagrama de tiempo:
(2) Ventajas y desventajas
Ventajas: La clase de cliente y la clase de fábrica están separadas. Los consumidores necesitan un determinado producto en cualquier momento, solo solicítelo a la fábrica. Los consumidores pueden aceptar nuevos productos sin modificaciones.
Desventaja: cuando se modifica el producto, la clase de fábrica también debe modificarse en consecuencia.
Método de fábrica
Solía llevar a mi esposa a Uniqlo (simple fábrica) a comprar ropa, con tantos estilos, ella se molestaba cuando iba de compras con más frecuencia. Luego cambié de estrategia y llevé a mi esposa al centro comercial (fábrica abstracta), hay tiendas de varias marcas en el centro comercial, sin mí ella puede ir de compras todo el día.
A diferencia de las fábricas simples, la categoría de fábrica central (centros comerciales) ya no es responsable de la creación de todos los productos, sino que delega el trabajo de creación específico a las subcategorías (tiendas de ropa), convirtiéndose en un papel de fábrica abstracto, solo responsable de dar categorías de fábrica específicas. La interfaz (tienda) que debe implementarse sin tocar los detalles de qué clase de producto debe instanciarse.
(1) Estructura del patrón del método de fábrica
El patrón del método de fábrica incluye los siguientes roles:
Producto: producto abstracto
ConcreteProduct: producto específico
Fábrica: Fábrica abstracta
ConcreteFactory: fábrica de hormigón
Diagrama de estructura:
Diagrama de tiempo:
Resumen del modo de fábrica
(1) Escenarios aplicables
Los productos exportados son productos estándar, cualquiera puede hacerlo.
(2) Ejemplos
La fábrica de conexiones de base de datos común, SqlSessionFactory, es una conexión de base de datos. En cuanto a si es proporcionada por Oracle o mysql, no necesito preocuparme, porque me permite manipular datos a través de SQL.
(3) Asuntos que necesitan atención
Al comienzo del proyecto, cuando la estructura y los requisitos del software no son estables, no se recomienda utilizar este modo, ya que sus desventajas también son obvias, aumentando la complejidad del código, aumentando el nivel de llamada y aumentando la carga de memoria. Así que presta atención para evitar el abuso del modelo.
(4) Implementación simple
package FactoryMethod;
public class FactoryPattern
{
public static void main(String[] args)
{
Factory factory = new ConcreteFactoryA();
Product product = factory.createProduct();
product.use();
}
}
//抽象产品:提供了产品的接口
interface Product
{
public void use();
}
//具体产品A:实现抽象产品中的抽象方法
class ConcreteProductA implements Product
{
public void use()
{
System.out.println("具体产品A显示...");
}
}
//具体产品B:实现抽象产品中的抽象方法
class ConcreteProductB implements Product
{
public void use()
{
System.out.println("具体产品B显示...");
}
}
//抽象工厂:提供了厂品的生成方法
interface Factory
{
public Product createProduct();
}
//具体工厂A:实现了厂品的生成方法
class ConcreteFactoryA implements AbstractFactory
{
public Product createProduct()
{
System.out.println("具体工厂A生成-->具体产品A.");
return new ConcreteProductA();
}
}
//具体工厂B:实现了厂品的生成方法
class ConcreteFactoryB implements AbstractFactory
{
public Product createProduct()
{
System.out.println("具体工厂B生成-->具体产品B.");
return new ConcreteProductB();
}
}
2 modo Singleton (Singleton)
Wei Xiaobao tiene 7 esposas, pero cada una es solo su esposo, cuando todas sus esposas se llaman esposos, se refieren a él, y él es un solo caso.
Estructura del modo singleton
El modo singleton incluye los siguientes roles:
Singleton: Singleton
Diagrama de estructura:
Diagrama de tiempo:
Pros y contras
Ventajas: solo hay una instancia a nivel mundial, lo que es conveniente para el control unificado y reduce la sobrecarga de recursos del sistema.
Desventajas: Sin capa de abstracción, difícil de expandir.
Escenarios de aplicación
Es adecuado para escenarios que requieren un control unificado global, como un generador de código único a nivel mundial.
Precauciones
Solo se proporcionan métodos públicos getInstance al mundo exterior y no se proporcionan constructores públicos.
Implementación simple
public class Singleton
{
private static volatile Singleton instance=null; //保证 instance 在所有线程中同步
private Singleton(){} //private 避免类在外部被实例化
public static synchronized Singleton getInstance()
{
//getInstance 方法前加同步
if(instance == null)
{
instance = new Singleton();
}
return instance;
}
}
3 Decorador
Después de graduarme de la universidad, quería darle a mi compañero de cuarto un regalo conmemorativo. Encontré una foto de todos y escribí "¡Hermano para siempre!". Luego la llevé a la tienda de regalos, instalé un marco de fotos y lo envolví en una caja de regalo. La tienda de regalos y yo somos decoradores, ninguno ha cambiado la foto en sí, pero ambos hicieron que la foto fuera más adecuada como regalo.
Estructura del patrón de decoración
El modo de decoración incluye los siguientes roles:
Componente: componente abstracto
ConcreteComponent: componente de hormigón
Decorador: clase de decoración abstracta
ConcreteDecorator: clase de decoración de hormigón
Diagrama de estructura:
Diagrama de tiempo:
Pros y contras
Ventajas: más flexible que la herencia (la herencia es una relación estática con un alto grado de acoplamiento), puede agregar responsabilidades dinámicamente al objeto y puede extender N nuevas funciones para el objeto usando diferentes combinaciones de decoradores sin afectar el objeto en sí.
Desventajas: Cuando hay demasiados decoradores para un objeto, se generarán una gran cantidad de pequeños objetos decorativos y estrategias de combinación de decoración, aumentando la complejidad del sistema y aumentando el costo de lectura y comprensión del código.
Escena aplicable
Es adecuado para escenas que necesitan (a través de la configuración, como el diamante) aumentar o disminuir dinámicamente las funciones del objeto.
Adecuado para escenas donde un objeto requiere N tipos de permutaciones y combinaciones funcionales (si se usa la herencia, el número de subclases explotará)
Precauciones
La interfaz de una clase decorada debe seguir siendo la misma que la interfaz de la clase decorada Para el cliente, tanto el objeto antes de la decoración como el objeto después de la decoración pueden tratarse de forma coherente.
Intente mantener la clase de componente concreto Component como una clase "ligera", es decir, no ponga demasiada lógica y estado en la clase de componente concreto, puede usar la clase de decoración.
Implementación simple
package decorator;
public class DecoratorPattern
{
public static void main(String[] args)
{
Component component = new ConcreteComponent();
component.operation();
System.out.println("---------------------------------");
Component decorator = new ConcreteDecorator(component);
decorator.operation();
}
}
//抽象构件角色
interface Component
{
public void operation();
}
//具体构件角色
class ConcreteComponent implements Component
{
public ConcreteComponent()
{
System.out.println("创建具体构件角色");
}
public void operation()
{
System.out.println("调用具体构件角色的方法operation()");
}
}
//抽象装饰角色
class Decorator implements Component
{
private Component component;
public Decorator(Component component)
{
this.component=component;
}
public void operation()
{
component.operation();
}
}
//具体装饰角色
class ConcreteDecorator extends Decorator
{
public ConcreteDecorator(Component component)
{
super(component);
}
public void operation()
{
super.operation();
addBehavior();
}
public void addBehavior()
{
System.out.println("为具体构件角色增加额外的功能addBehavior()");
}
}
4 Modo de estrategia (Estrategia)
Los niños suelen usar este modelo cuando persiguen a las niñas. Las estrategias comunes incluyen estas: comer en una cita; ver una película; ver un concierto; ir de compras; ir de viaje ... Aunque hacen cosas diferentes, pueden reemplazarse entre sí. El único objetivo Todos están capturando los corazones de las niñas.
Estructura del modo de estrategia
Contexto: clase de entorno
Estrategia: clase de estrategia abstracta
ConcreteStrategy: clase de estrategia específica
Diagrama de estructura:
Diagrama de tiempo:
Pros y contras
Ventajas: El modo de estrategia proporciona un soporte perfecto para el "principio de apertura y cierre", y los usuarios pueden elegir algoritmos o comportamientos sin modificar el sistema original. Mata al complejo y feo if-else.
Desventajas: Al llamar, debe saber de antemano qué clases de modos de estrategia están disponibles para decidir por sí mismo qué estrategia debe usarse en la escena actual.
Escenario de prueba
Un sistema necesita seleccionar dinámicamente uno de varios algoritmos alternativos. Los usuarios no quieren preocuparse por los detalles del algoritmo y encapsular el algoritmo específico en una clase de estrategia.
Precauciones
Asegúrese de explicar el propósito y los escenarios aplicables de la estrategia en los comentarios de la clase de estrategia.
Implementación simple
package strategy;
public class StrategyPattern
{
public static void main(String[] args)
{
Context context = new Context();
Strategy strategyA = new ConcreteStrategyA();
context.setStrategy(strategyA);
context.algorithm();
System.out.println("-----------------");
Strategy strategyB = new ConcreteStrategyB();
context.setStrategy(strategyB);
context.algorithm();
}
}
//抽象策略类
interface Strategy
{
public void algorithm(); //策略方法
}
//具体策略类A
class ConcreteStrategyA implements Strategy
{
public void algorithm()
{
System.out.println("具体策略A的策略方法被访问!");
}
}
//具体策略类B
class ConcreteStrategyB implements Strategy
{
public void algorithm()
{
System.out.println("具体策略B的策略方法被访问!");
}
}
//环境类
class Context
{
private Strategy strategy;
public Strategy getStrategy()
{
return strategy;
}
public void setStrategy(Strategy strategy)
{
this.strategy=strategy;
}
public void algorithm()
{
strategy.algorithm();
}
}
5 Modo proxy (Proxy)
El servicio al cliente de la tienda de Taobao siempre recibirá muchas preguntas repetidas, como: ¿Hay existencias? ¿Cuándo se enviará? ¿Qué tipo de envío urgente? Responder una gran cantidad de preguntas repetitivas era demasiado molesto, por lo que apareció el robot Xiaomi, vino a ayudar al servicio al cliente a responder esas preguntas conocidas, y cuando se encontraba con una pregunta que Xiaomi no podía responder, acudía al servicio al cliente manual. El robot Xiaomi aquí es el agente de servicio al cliente.
Estructura del modelo de agencia
El modo proxy incluye los siguientes roles:
Asunto: Rol del tema abstracto
Proxy: rol de tema de proxy
RealSubject: Rol del sujeto real
Diagrama de estructura:
Diagrama de tiempo:
Pros y contras
Ventajas: El agente puede coordinar la persona que llama y la persona que llama, lo que reduce el acoplamiento del sistema. Según los diferentes tipos de agentes y escenarios, puede desempeñar un papel en el control de la seguridad y reducir la sobrecarga del sistema.
Desventajas: Se agrega una capa de procesamiento proxy, lo que aumenta la complejidad del sistema y puede reducir la velocidad correspondiente del sistema.
Escenario de prueba
En teoría, puede representar cualquier objeto. Los modos de proxy comunes son:
Proxy remoto: proporcione un objeto de proxy local para un objeto ubicado en un espacio de direcciones diferente. Este espacio de direcciones diferente puede estar en el mismo host o en otro host. El proxy remoto también se llama embajador ( Embajador).
Agente virtual: Si necesitas crear un objeto que consume muchos recursos, primero crea un objeto que consume una cantidad relativamente pequeña para representarlo, el objeto real solo se creará cuando sea necesario.
Agente de copia en escritura: es un tipo de agente virtual que retrasa la operación de copia (clonación) hasta que se ejecuta solo cuando el cliente realmente lo necesita. En términos generales, la clonación profunda de un objeto es una operación costosa. El agente de copia en escritura puede retrasar esta operación y el objeto se clona solo cuando se utiliza.
Agente de protección (protección o acceso): controla el acceso a un objeto y puede proporcionar diferentes niveles de acceso a diferentes usuarios.
Agente de caché: proporcione espacio de almacenamiento temporal para los resultados de una determinada operación de destino, de modo que varios clientes puedan compartir estos resultados.
Proxy de firewall (firewall): protege el objetivo de usuarios malintencionados.
Agente de sincronización (Sincronización): permite que varios usuarios utilicen un objeto al mismo tiempo sin conflictos.
Agente de referencia inteligente: cuando se hace referencia a un objeto, proporciona algunas operaciones adicionales, como registrar el número de veces que se llama al objeto.
Implementación simple
package proxy;
public class ProxyPattern
{
public static void main(String[] args)
{
Proxy proxy = new Proxy();
proxy.request();
}
}
//抽象主题
interface Subject
{
void request();
}
//真实主题
class RealSubject implements Subject
{
public void request()
{
System.out.println("访问真实主题方法...");
}
}
//代理
class Proxy implements Subject
{
private RealSubject realSubject;
public void request()
{
if (realSubject==null)
{
realSubject=new RealSubject();
}
preRequest();
realSubject.request();
afterRequest();
}
public void preRequest()
{
System.out.println("访问真实主题之前的预处理。");
}
public void afterRequest()
{
System.out.println("访问真实主题之后的后续处理。");
}
}
6 Modo de observador (Observador)
Estás en un viaje de negocios y quieres conocer la situación de tu hijo en casa. En este momento, solo necesitas unirte al grupo "familia familiar". Las mamás y los papás a menudo publican fotos y videos de sus hijos en el grupo. Todo lo que tienes que hacer es ser un observador, Puede comprender todo con solo deslizar la información en el grupo.
Estructura del patrón de observador
El modo de observador incluye los siguientes roles:
Asunto: objetivo
ConcreteSubject: objetivo específico
Observador: Observador
ConcreteObserver: observador específico
Diagrama de estructura:
Diagrama de tiempo:
Pros y contras
Ventajas: Convierta la compleja lógica de procesamiento en serie en una lógica de procesamiento independiente unificada. Los observadores simplemente envían mensajes de acuerdo con su propia lógica y no les importa quién consume los mensajes. Cada observador solo se ocupa de lo que le importa. El aislamiento lógico aporta una estructura de código simple y refrescante.
Desventajas: cuando hay muchos observadores, es posible que se gaste una cierta cantidad de gastos generales para enviar un mensaje, pero el mensaje solo puede ser consumido por un observador.
Escena aplicable
Es adecuado para escenarios de negocios de uno a varios. Cuando un objeto cambia, activará N objetos para realizar el procesamiento correspondiente. Por ejemplo: notificación de programación de pedidos, cambio de estado de tareas, etc.
Precauciones
Evite formar una dependencia circular entre el observador y lo observado, lo que puede hacer que el sistema se bloquee.
Implementación simple
package observer;
import java.util.*;
public class ObserverPattern
{
public static void main(String[] args)
{
Subject subject = new ConcreteSubject();
Observer obsA = new ConcreteObserverA();
Observer obsb = new ConcreteObserverB();
subject.add(obsA);
subject.add(obsB);
subject.setState(0);
}
}
//抽象目标
abstract class Subject
{
protected List<Observer> observerList = new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer)
{
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer)
{
observers.remove(observer);
}
public abstract void notify(); //通知观察者方法
}
//具体目标
class ConcreteSubject extends Subject
{
private Integer state;
public void setState(Integer state){
this.state = state;
// 状态改变通知观察者
notify();
}
public void notify()
{
System.out.println("具体目标状态发生改变...");
System.out.println("--------------");
for(Observer obs:observers)
{
obs.process();
}
}
}
//抽象观察者
interface Observer
{
void process(); //具体的处理
}
//具体观察者A
class ConcreteObserverA implements Observer
{
public void process()
{
System.out.println("具体观察者A处理!");
}
}
//具体观察者B
class ConcreteObserverB implements Observer
{
public void process()
{
System.out.println("具体观察者B处理!");
}
}
No hay manera, pero la técnica se puede lograr; si no hay manera, termina con la técnica.
Bienvenidos a todos a seguir la cuenta pública de Java Way
Buen artículo, estoy leyendo ❤️