Patrones detallados de diseño de software

1. Descripción general de los patrones de diseño de software

El patrón de diseño (Design Pattern) es un resumen de la experiencia de desarrollo de código, que se utiliza para mejorar la reutilización del código, la mantenibilidad, la legibilidad, la solidez y las soluciones de seguridad.
En 1995, GoF (Gang of Four, un grupo de cuatro / pandillas de cuatro) coeditó el libro "Patrones de diseño: la base del software orientado a objetos reutilizables", que incluía un total de 23 patrones de diseño, y así estableció el campo de los patrones de diseño de software. Hito, conocido como "patrón de diseño GoF".
La esencia de estos 23 patrones de diseño es la aplicación práctica de los principios de diseño orientado a objetos, y una comprensión completa de la encapsulación, herencia y polimorfismo de las clases, así como la asociación y composición de clases. .

La imagen proviene de http://c.biancheng.net
El patrón de diseño es solo una guía: en el desarrollo de software real, se puede seleccionar de acuerdo con las necesidades específicas y también se puede usar en otros lenguajes de programación orientados a objetos.

  • Puede mejorar la capacidad de pensamiento del programador, la capacidad de programación y la capacidad de diseño.
  • Hace que el diseño del programa sea más estandarizado y la preparación del código más ingeniería, lo que mejora en gran medida la eficiencia del desarrollo de software y acorta el ciclo de desarrollo de software.
  • Haga que el código diseñado sea reutilizable, legible, confiable, flexible y fácil de mantener.

Elementos básicos de los patrones de diseño de software.

  1. Nombre del patrón
  2. Problema
  3. Solución
  4. Efecto (Conquence)

Segundo, la clasificación de los patrones de diseño.

1. Según el propósito

  • El modo de creación se
    utiliza para describir cómo crear objetos y separar la creación y el uso de los objetos.Hay cinco modos de creación: singleton, prototipo, método de fábrica, fábrica abstracta y constructor.
  • Los patrones estructurales se
    utilizan para describir cómo clasificar objetos y objetos en una estructura más grande en un diseño determinado. Hay siete patrones estructurales como proxy, adaptador, puente, decoración, apariencia, peso mosca y combinación.
  • El modo de comportamiento se
    usa para describir cómo las clases y los objetos cooperan entre sí para completar tareas.Hay once comportamientos: métodos de plantilla, estrategias, comandos, cadenas de responsabilidad, estados] observadores, intermediarios, iteradores, visitantes, notas, intérpretes, etc. Modelo.

2. Según el alcance de la acción

  • Los patrones de clase se
    utilizan para manejar la relación entre clases y subclases. Estas relaciones se establecen a través de la herencia estática. Hay patrones de clase como métodos de fábrica, adaptadores e intérpretes de métodos de plantilla.
  • El modo de objeto se
    usa para tratar la relación entre objetos. Estas relaciones se pueden lograr mediante combinación o agregación. Se puede cambiar en tiempo de ejecución. Excepto por los cuatro anteriores, el otro es el modo de objeto.

Tabla de clasificación de patrones de diseño

Alcance \ Propósito Modo de creación Modelo estructural Modelo de comportamiento
Patrón de clase Método de fábrica Adaptador Métodos de plantilla, intérpretes
Modo de objeto Singleton
prototype
abstract factory
constructor
(Objeto) La apariencia de la decoración del
puente del adaptador disfruta de la combinación de yuan



Política
comando
responsabilidad cadena
estado
observador
intermediario
iterador
visitante
memo

Tercero, la función del patrón de diseño.

  1. Modo Singleton (Singleton): una clase solo puede generar una instancia, la clase proporciona un punto de acceso global para acceso externo a la instancia, su expansión se limita al modo de casos múltiples.
  2. Modo prototipo: tome un objeto como prototipo y clone varias instancias nuevas similares al prototipo copiándolo.
  3. Modo Método de fábrica: defina una interfaz para crear productos, y las subclases deciden qué productos se producen.
  4. Modo Abstract Factory (AbstractFactory): proporciona una interfaz para crear familias de productos, cada una de las cuales puede producir una serie de productos relacionados.
  5. Modo de generador: descomponga un objeto complejo en varias partes relativamente simples, luego créelos por separado de acuerdo con las diferentes necesidades y finalmente construya en el objeto complejo.
  6. Modo proxy: proporcione un proxy para que un objeto controle el acceso al objeto. Es decir, el cliente accede al objeto indirectamente a través del proxy, restringiendo, mejorando o modificando algunas características del objeto.
  7. Modo de adaptador: convierta la interfaz de una clase en otra interfaz que el cliente desee, de modo que las clases que no puedan funcionar juntas debido a interfaces incompatibles puedan funcionar juntas.
  8. Modo puente: abstracción e implementación separadas para que puedan cambiar de forma independiente. Se realiza combinando la relación en lugar de la relación de herencia, reduciendo así el acoplamiento entre las dos dimensiones variables de abstracción y realización.
  9. Modo decorador: agrega dinámicamente algunas responsabilidades al objeto, es decir, agrega funciones adicionales.
  10. Modo de fachada: proporciona una interfaz consistente para múltiples subsistemas complejos, lo que facilita el acceso a estos subsistemas.
  11. Modo Flyweight (Flyweight): el uso de la tecnología de compartir para apoyar de manera efectiva la reutilización de una gran cantidad de objetos de grano fino.
  12. Modo compuesto: la combinación de objetos en una estructura jerárquica en forma de árbol permite a los usuarios tener acceso constante a objetos individuales y objetos compuestos.
  13. Modo Método de plantilla: defina el esqueleto del algoritmo en una operación y retrase algunos pasos del algoritmo a la subclase, de modo que la subclase pueda redefinir algunos pasos específicos del algoritmo sin cambiar la estructura del algoritmo.
  14. Modo de estrategia (estrategia): defina una serie de algoritmos y encapsule cada algoritmo, para que puedan reemplazarse entre sí, y el cambio del algoritmo no afectará a los clientes que usan el algoritmo.
  15. Modo de comando: una solicitud se encapsula como un objeto, de modo que la responsabilidad de emitir la solicitud se separa de la responsabilidad de ejecutar la solicitud.
  16. Modo de cadena de responsabilidad (cadena de responsabilidad): la solicitud se pasa de un objeto al siguiente en la cadena hasta que se responde la solicitud. De esta forma, se elimina el acoplamiento entre objetos.
  17. Modo de estado: permite que un objeto cambie su capacidad de comportamiento cuando cambia su estado interno.
  18. Modo observador: existe una relación de uno a muchos entre varios objetos. Cuando un objeto cambia, el cambio se notifica a otros objetos múltiples, lo que afecta el comportamiento de otros objetos.
  19. Modo de mediador: defina un objeto intermediario para simplificar la interacción entre los objetos originales, reduzca el acoplamiento entre los objetos en el sistema, de modo que los objetos originales no tengan que entenderse entre sí.
  20. Modo iterador: proporciona un método para acceder secuencialmente a una serie de datos en un objeto agregado sin exponer la representación interna del objeto agregado.
  21. Modo de visitante: proporciona múltiples métodos de acceso para cada elemento de una colección sin cambiar los elementos de la colección, es decir, cada elemento tiene acceso de objeto de visitante múltiple.
  22. Modo Memo (Memento): sin destruir la encapsulación, obtenga y guarde el estado interno de un objeto para poder restaurarlo más tarde.
  23. Modo de intérprete (Intérprete): proporciona cómo definir la gramática del lenguaje, así como la interpretación de las oraciones del lenguaje, es decir, el intérprete.

4. Explicación detallada de patrones de diseño comunes.

4.1 Modo Singleton

  • Definición de modo: asegúrese de que solo haya una instancia de una clase y proporcione un punto de acceso global
  • Escenario: objetos pesados ​​que no requieren varias instancias, como grupos de subprocesos y grupos de conexiones de bases de datos
  • Método de implementación:
  1. Modo diferido: carga diferida, solo se inicializa cuando realmente se usa

Programa de demostración de subproceso único

package edu.sust.designpattern;

public class LazySingletonTest {
    public static void main(String[] args) {
        LazySingleton instance1 = LazySingleton.getInstance();
        LazySingleton instance2 = LazySingleton.getInstance();
        System.out.println(instance1 == instance2);//true
    }
}

class LazySingleton {
    private static LazySingleton instance;//实例

    private LazySingleton() {
    }

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

En un entorno multiproceso

package edu.sust.designpattern;

public class LazySingletonTest {
    public static void main(String[] args) {
        new Thread(() -> {
            LazySingleton instance = LazySingleton.getInstance();
            System.out.println(instance);
        }).start();
        new Thread(() -> {
            LazySingleton instance = LazySingleton.getInstance();
            System.out.println(instance);
        }).start();
    }
}

class LazySingleton {
    private static LazySingleton instance;//实例

    private LazySingleton() {//私有的构造函数,类外无法使用构造实例
    }

    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new LazySingleton();
        }
        return instance;
    }
}
  1. Modelo de hombre hambriento: la inicialización de la clase se completa en la etapa de inicialización de la instancia. Esencialmente, utiliza el mecanismo de carga de clase de la JVM para garantizar la unicidad de la clase.

Proceso de carga de clase:

  • Cargue datos binarios en la memoria y genere la estructura de datos de clase correspondiente

  • Conectar: ​​a. Verificar b. Preparar (asignar valores predeterminados a las variables miembro estáticas de la clase) c. Resolver

  • Inicialización: asigne valores iniciales a variables estáticas de la clase

package edu.sust.designpattern;

public class HungrySingletonTest {
    public static void main(String[] args) {
        HungrySingleton instance1 = HungrySingleton.getInstance();
        HungrySingleton instance2 = HungrySingleton.getInstance();
        System.out.println(instance1==instance2);//true
    }
}

class HungrySingleton {
    private static HungrySingleton instance = new HungrySingleton();

    private HungrySingleton() {
    }

    public static HungrySingleton getInstance() {
        return instance;
    }
}
  1. Implementación de clase interna estática
    • Utilice esencialmente el mecanismo de carga de clase para garantizar la seguridad del hilo
    • La inicialización de la clase se activa solo cuando se usa realmente, por lo que también es una forma de carga diferida
package edu.sust.designpattern;

public class InnerClassSingletonTest {
    public static void main(String[] args) {
        //单线程环境下
        InnerClassSingleton instance1 = InnerClassSingleton.getInstance();
        InnerClassSingleton instance2 = InnerClassSingleton.getInstance();
        System.out.println(instance1 == instance2);//true
        //多线程环境下
        new Thread(() -> {
            InnerClassSingleton instanceI = InnerClassSingleton.getInstance();
            System.out.println(instanceI);
        }).start();
        new Thread(() -> {
            InnerClassSingleton instanceII = InnerClassSingleton.getInstance();
            System.out.println(instanceII);
        }).start();
    }
}

class InnerClassSingleton {
    private static class InnerClassHolder {//静态内部类
        private static InnerClassSingleton instance = new InnerClassSingleton();
    }

    private InnerClassSingleton() {
    }

    public static InnerClassSingleton getInstance() {
        return InnerClassHolder.instance;
    }
}

4.2 Patrón de método de fábrica

  • Definición de esquema: una interfaz para crear objetos, permitiendo que las subclases decidan qué clase instanciar. El patrón del método de fábrica retrasa la creación de instancias de clases en subclases.
  • Escenario de aplicación:
    1. Cuando no sabe el tipo exacto del objeto a utilizar
    2. Cuando desee proporcionar un método para que una biblioteca o marco amplíe sus componentes internos
  • Los puntos principales son:
    1. Desacoplar productos y creadores específicos
    2. Cumplir con el principio de responsabilidad única
    3. Conoce el principio de apertura y cierre
  • Programación orientada a la implementación.
package edu.sust.designpattern;

public class FactoryMethod {
    public static void main(String[] args) {
        Application application = new Application();
        ProductA object = application.getObject();
        object.method();
    }
}

class ProductA {
    public void method() {
        System.out.println("ProductA.method executed...");
    }
}

class Application {
    private ProductA createProduct() {
        return new ProductA();
    }

    ProductA getObject() {
        ProductA productA = new ProductA();
        return productA;
    }
}

4.3 Patrón abstracto de fábrica

  • Definición de patrón: proporcione una interfaz para crear una serie de objetos relacionados o interdependientes sin especificar sus clases específicas

  • Escenario de aplicación: el programa debe tratar con diferentes series de productos relacionados, pero no desea que dependa de
    la implementación específica de estos productos, puede usar una fábrica abstracta

  • Ventajas:

    1. Puede estar seguro de que los productos que obtiene de fábrica son compatibles entre sí
    2. Puede evitar un acoplamiento estrecho entre productos específicos y código de cliente
    3. Cumplir con el principio de responsabilidad única
    4. Conoce el principio de apertura y cierre
    package edu.sust.designpattern;
    
    public class AbstractFactoryTest {
        public static void main(String[] args) {
            IDatabaseUtils iDatabaseUtils = new MySQLDatabaseUtils();
            IConnection iConnection = iDatabaseUtils.getConnection();
            iConnection.connect();
            ICommand iCommand = iDatabaseUtils.getCommand();
            iCommand.command();
        }
    }
    
    interface IConnection {
        void connect();
    }
    
    class MySQLConnection implements IConnection {
        @Override
        public void connect() {
            System.out.println("MySQL connected");
        }
    }
    
    interface ICommand {
        void command();
    }
    
    class MySQLCommand implements ICommand {
        @Override
        public void command() {
            System.out.println("MySQL command");
        }
    }
    
    interface IDatabaseUtils {
        ICommand getCommand();
    
        IConnection getConnection();
    }
    
    class MySQLDatabaseUtils implements IDatabaseUtils {
        @Override
        public ICommand getCommand() {
            return new MySQLCommand();
        }
    
        @Override
        public IConnection getConnection() {
            return new MySQLConnection();
        }
    }
    

4.4 Modo de constructor

  • Definición de modo: separe la creación de un objeto complejo de su representación para que el mismo proceso de construcción pueda crear diferentes representaciones

  • Escenario de aplicación:

    1. El objeto a generar tiene una estructura interna compleja

    2. Las propiedades internas de los objetos que deben generarse dependen unas de otras.

    3. Usar con objetos inmutables

  • Ventajas:

    1. El constructor es independiente y fácil de expandir.

    2. Facilitar el control de los riesgos detallados.

4.5 Modo prototipo

  • Definición de modo: se refiere a la instancia del prototipo que especifica el tipo de objeto creado, y copiando estos prototipos para crear nuevos objetos.

  • y Escenario de aplicación: cuando el código no debe depender de la clase específica del objeto a copiar, use el modo prototipo

  • Ventajas:

    1. Puede clonar objetos sin acoplar clases específicas

    2. Evite el código de inicialización repetido

    3. Construcción más conveniente de objetos complejos.

Publicado 395 artículos originales · ganó 130 · 200,000 vistas +

Supongo que te gusta

Origin blog.csdn.net/qq_40507857/article/details/103666216
Recomendado
Clasificación