Patrones de diseño - Introducción a los patrones de diseño y al patrón de diseño Singleton

 navegación: 

[Dark Horse Java Notes + Stepping on the Pit Summary] JavaSE+JavaWeb+SSM+SpringBoot+Riji Takeaway+SpringCloud+Dark Horse Tourism+Guli Mall+Xuecheng Online+Design Mode+Nioke Interview Questions

 

Tabla de contenido  

1. Resumen y clasificación de patrones de diseño

1.1 Introducción a los patrones de diseño

1.2 Clasificación de patrones de diseño

2. Patrón de diseño creacional - patrón singleton

2.1 Introducción

2.2 Cómo crear ocho patrones singleton

2.2.1 Estilo hambriento (constante estática)

2.2.2 Estilo hambriento (bloque de código estático)

2.2.3 Estilo perezoso (subproceso inseguro)

2.2.4 Estilo perezoso (métodos sincronizados seguros para subprocesos)

2.2.5 Estilo perezoso (subproceso inseguro, bloques de código sincronizados)

2.2.6 Verificación doble (recomendado, seguro para subprocesos, carga diferida)

2.2.7 Clase interna estática (recomendado)

2.2.8 Enumeración (recomendado)

2.2.9 Análisis del modo singleton en el código fuente de JDK


1. Resumen y clasificación de patrones de diseño

1.1 Introducción a los patrones de diseño

  • 1) El patrón de diseño es la experiencia útil resumida por los programadores frente a problemas similares de diseño de ingeniería de software. Los patrones no son códigos, sino soluciones generales para ciertos tipos de problemas , y los patrones de diseño representan las mejores prácticas. Estas soluciones son el resultado del ensayo y error de numerosos desarrolladores de software durante un período de tiempo considerable.
  • 2) La esencia del patrón de diseño mejora la capacidad de mantenimiento, la versatilidad y la escalabilidad del software , y reduce la complejidad del software.
  • 3) "Patrones de diseño" es un libro clásico escrito por Erich Gamma, Richard Helm, Ralph Johnson y John Vlissides Design (comúnmente conocido como "Group of Four GOF")
  • 4) Los patrones de diseño no se limitan a un determinado idioma, Java, PHP y C++ tienen patrones de diseño

1.2 Clasificación de patrones de diseño

En los patrones de diseño, generalmente se divide en tres tipos de patrones de diseño, que son patrones de creación, patrones estructurales y patrones de comportamiento.

  • Patrones de creación : se utilizan principalmente para la creación de objetos , incluidos múltiples patrones diferentes, como el patrón de método de fábrica, el patrón de fábrica abstracto, el patrón de construcción, el patrón de singleton y el patrón de prototipo. Estos patrones ayudan a reducir el acoplamiento del sistema y mejoran la reutilización y la escalabilidad del código.

  • Patrones estructurales : se utilizan principalmente para describir la relación de combinación entre objetos , incluidos varios patrones diferentes, como "patrón de proxy", "patrón de adaptador", "patrón de puente", "patrón de decorador", "modo de apariencia", "modo de peso ligero" y "modo de combinación", etc. Estos patrones pueden ayudarnos a diseñar mejor la estructura del programa y mejorar la flexibilidad y la mantenibilidad del código.

  • Patrones de comportamiento : se utilizan principalmente para describir la comunicación y la asignación de responsabilidades entre objetos , incluidos múltiples patrones diferentes, como "patrón de estrategia", "patrón de método de plantilla", "patrón de observador", "patrón de iterador", "Modo de cadena de responsabilidad", " Modo Comando", "Modo Visitante", "Modo Memo" y "Modo Intérprete", etc. Estos patrones se utilizan a menudo para implementar diferentes algoritmos, procesos y métodos de comunicación para lograr una mayor flexibilidad y capacidad de mantenimiento del sistema.

Hay tres tipos de patrones de diseño.

  • Patrones de creación : patrón singleton, patrón de fábrica abstracto, patrón de prototipo, patrón de constructor, patrón de fábrica
  • Patrones estructurales : patrón de adaptador, patrón de puente, patrón de decoración , patrón compuesto, patrón de apariencia, patrón de peso ligero, patrón de proxy
  • Patrones de comportamiento : patrón de método de plantilla , patrón de comando, patrón de visitante, patrón de iterador, patrón de observador, patrón de intermediario, patrón de memo, patrón de intérprete (patrón de intérprete), patrón de estado, patrón de estrategia, patrón de cadena de responsabilidad (modelo de cadena de responsabilidad)

Nota: Hay ligeras diferencias en la clasificación y los nombres en diferentes libros.

2. Patrón de diseño creacional - patrón singleton

2.1 Introducción

El llamado patrón de diseño singleton de una clase consiste en adoptar un determinado método para garantizar que, en todo el sistema de software, solo puede haber una instancia de objeto para una determinada clase , y esta clase solo proporciona un método (método estático) para obtener su instancia de objeto.

Como SessionFactory de Hibernate, que actúa como un proxy para las fuentes de almacenamiento de datos y es responsable de crear objetos de sesión. SessionFactory no es liviano. En general, un proyecto generalmente solo necesita una SessionFactory , que usará el modo singleton

ventaja:

  • Ahorro de recursos: solo hay una instancia del patrón singleton, que puede evitar la creación repetida de objetos , ahorrando así recursos y mejorando el rendimiento del sistema.
  • Administrar variables globales: el patrón singleton se puede usar para administrar el estado global y las variables para facilitar el intercambio de datos en todo el sistema .
  • Simplificar la arquitectura del sistema: el uso del patrón singleton puede simplificar la arquitectura del sistema, reducir la cantidad de clases y la complejidad de la interfaz.

defecto:

  1. Puede causar problemas de simultaneidad: cuando el modo singleton se usa en subprocesos múltiples, debe garantizar la seguridad de los subprocesos; de lo contrario, puede causar problemas de simultaneidad.
  2. Puede aumentar la complejidad del sistema: el uso excesivo del patrón singleton puede aumentar la complejidad del sistema, lo que dificulta el mantenimiento del código.
  3. Difícil de depurar: debido al estado compartido global del modo singleton, puede causar problemas durante la depuración que son difíciles de localizar y probar.

 Precauciones y escenarios de uso

  • 1) El modo singleton garantiza que solo exista un objeto de esta clase en la memoria del sistema, lo que ahorra recursos del sistema Para algunos objetos que deben crearse y destruirse con frecuencia, el uso del modo singleton puede mejorar el rendimiento del sistema
  • 2) Cuando desee instanciar una clase singleton, debe recordar usar el método correspondiente para obtener el objeto en lugar de usar new
  • 3) Escenarios para el modo singleton: objetos que necesitan ser creados y destruidos con frecuencia, objetos que toman demasiado tiempo para crear o consumen demasiados recursos pero se usan con frecuencia (es decir, objetos pesados), objetos de herramientas, objetos que acceden con frecuencia a bases de datos o archivos (como fuentes de datos, fábricas de sesiones, etc.)

2.2 Cómo crear ocho patrones singleton

  • 1) Estilo chino hambriento (constante estática): seguro para subprocesos, la memoria se desperdiciará si no se usa.
  • 2) Estilo chino hambriento (bloque de código estático): seguro para subprocesos, desperdiciará memoria si no se usa.
  • 3) Estilo perezoso (subproceso inseguro): carga diferida, subproceso inseguro. Es decir, cree una instancia cuando se use, y se pueden crear varias instancias cuando se utilicen subprocesos múltiples. No lo uses de esta manera.
  • 4) Estilo perezoso (seguridad de subprocesos, método de sincronización): seguridad de subprocesos, pero baja eficiencia (bloqueo cada vez que se adquiere una instancia), no recomendado.
  • 5) Estilo perezoso (los subprocesos no son seguros, bloques de código sincronizados): los subprocesos no son seguros, no use este método.
  • 6) Verifique dos veces
  • 7) Clase interna estática
  • 8) Enumeración

2.2.1 Estilo hambriento (constante estática)

Seguro para subprocesos, desperdiciará memoria si no se usa.

paso:

  1. Privatización de constructores (para evitar nuevos externos)
  2. Cree un objeto constante estático privado dentro de la clase
  3. Exponer un método público estático getInstance

public class Singleton {
    // 1、构造器私有化
    private Singleton() {
    }

    // 2、类的内部创建对象
    private static final Singleton instance = new Singleton();

    // 3、向外暴露一个静态的公共方法
    public static Singleton getInstance() {
        return instance;
    }
}

Ventajas y desventajas

  • Ventajas: Esta forma de escritura es relativamente simple, es decir, la instanciación se completa cuando se carga la clase (las variables de clase se asignarán durante las fases de preparación e inicialización de la carga de clases de JVM). Evita problemas de sincronización de subprocesos
  • Desventaja: La creación de instancias se completa cuando se carga la clase, lo que no logra el efecto de Lazy Loading . Si esta instancia nunca se usa desde el principio hasta el final, provocará un desperdicio de memoria.
  • Este método evita problemas de sincronización de subprocesos múltiples basados ​​en el mecanismo classloder. Sin embargo, la instancia se instancia cuando se carga la clase, y la mayor parte del modo singleton llama al método getlnstance, pero hay muchas razones para la carga de clases, por lo que no es seguro que haya otras formas (u otros métodos estáticos) para causar la clase para Loading, en este momento, inicializar la instancia no logra el efecto de Lazy loading
  • Conclusión: este modo singleton está disponible y puede causar desperdicio de memoria

2.2.2 Estilo hambriento (bloque de código estático)

Seguro para subprocesos, desperdiciará memoria si no se usa.

paso:

  1. privatización de constructores
  2. Referencias de objetos estáticos privados declarados internamente de la clase
  3. Instanciar un objeto en un bloque de código estático
  4. Exponer un método público estático

public class Singleton {
    // 1、构造器私有化
    private Singleton() {
    }

    // 2、类的内部声明对象
    private static Singleton instance;

    // 3、在静态代码块中创建对象
    static {
        instance = new Singleton();
    }

    // 4、向外暴露一个静态的公共方法
    public static Singleton getInstance() {
        return instance;
    }
}

Ventajas y desventajas

  • 1) Este método es en realidad similar al método de constante estática anterior, excepto que el proceso de creación de instancias de clase se coloca en el bloque de código estático , y cuando se carga la clase, el código en el bloque de código estático se ejecuta para inicializar la instancia de la clase Los pros y los contras son los mismos que los anteriores.
  • 2) Conclusión: este modo singleton está disponible, pero puede causar un desperdicio de memoria

2.2.3 Estilo perezoso (subproceso inseguro)

Lazy loading, no thread safe. Es decir, cree una instancia cuando se use, y se pueden crear varias instancias cuando se utilicen subprocesos múltiples. No lo uses de esta manera.

paso:

  1. privatización de constructores
  2. Cree una referencia de objeto estático privado dentro de la clase
  3. Exponga un método estático público al exterior y solo cree una instancia cuando se use este método

// 1、构造器私有化
private Singleton() {
}

// 2、类的内部声明对象
private static Singleton instance;

// 3、向外暴露一个静态的公共方法,当使用到该方法时,才去创建 instance
public static Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

Ventajas y desventajas

  • 1) Tiene el efecto de Lazy Loading , pero solo se puede usar bajo un solo hilo
  • 2) Si bajo subprocesos múltiples , un subproceso ingresa al bloque de declaración de juicio, y otro subproceso también pasa la declaración de juicio antes de que tenga tiempo de ejecutarse, entonces se
  • 3) Conclusión: en el desarrollo real, no use este método

2.2.4 Estilo perezoso (métodos sincronizados seguros para subprocesos)

Seguro para subprocesos, pero ineficiente (bloqueo cada vez que se adquiere una instancia), no recomendado.

  • 1) Privatización de constructores
  • 2) Crear objetos dentro de la clase.
  • 3) Exponer un método sincronizado estático público al exterior, y solo crear una instancia cuando se use este método

public class Singleton {
    // 1、构造器私有化
    private Singleton() {
    }

    // 2、类的内部声明对象
    private static Singleton instance;

    // 3、向外暴露一个静态的公共方法,加入同步处理的代码,解决线程安全问题
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Ventajas y desventajas

  • 1) Resolver el problema de la inseguridad del hilo.
  • 2) La eficiencia es demasiado baja , cuando cada hilo quiere obtener una instancia de la clase, getlnstance()se debe sincronizar el método de ejecución. De hecho, este método solo ejecuta el código de creación de instancias una vez, y si desea obtener una instancia de esta clase más tarde, puede returnhacerlo directamente. El método de sincronización es demasiado ineficiente
  • 3) Conclusión: en el desarrollo real, este método no se recomienda

2.2.5 Estilo perezoso (subproceso inseguro, bloques de código sincronizados)

El hilo no es seguro, no use este método.

  • 1) Privatización de constructores
  • 2) Crear objetos dentro de la clase.
  • 3) Exponer un método público estático al exterior y agregar un bloque de código para el procesamiento síncrono

public class Singleton {
    // 1、构造器私有化
    private Singleton() {
    }

    // 2、类的内部声明对象
    private static Singleton instance;

    // 3、向外暴露一个静态的公共方法,加入同步处理的代码,解决线程安全问题
    public static Singleton getInstance() {
        if (instance == null) {    //可能有多个线程同时通过检查,多次执行下面代码,产生多个实例
//类级别的锁对象,锁对象是全局的,对该类的所有实例均有效。回顾锁对象是this时仅限于锁当前实例
            synchronized (Singleton.class) {
                instance = new Singleton();
            }
        }
        return instance;
    }
}

Ventajas y desventajas

  • 1) Este método está destinado a mejorar el cuarto método de implementación, porque el método de sincronización anterior es demasiado ineficiente y se cambia para generar bloques de código instanciados de forma síncrona.
  • 2) Pero esta sincronización no juega el papel de sincronización de subprocesos. De acuerdo con la situación encontrada en el tercer método de implementación, si un subproceso ingresa al bloque de declaración de juicio y no tiene tiempo para ejecutarlo en el futuro, otro subproceso también pasa la declaración de juicio y se generarán varias instancias en este momento.
  • 3) Conclusión: en el desarrollo real, este método no se puede utilizar

2.2.6 Verificación doble (recomendado, seguro para subprocesos, carga diferida)

  1. privatización de constructores
  2. Las referencias a objetos se crean dentro de la clase y se modifican con la palabra clave volatile
  3. Exponga un método público estático al exterior, agregue bloques de código de procesamiento síncrono y realice juicios dobles para resolver problemas de seguridad de subprocesos.

public class Singleton {
    // 1、构造器私有化
    private Singleton() {
    }

    // 2、类的内部声明对象,同时用`volatile`关键字修饰,为了保证可见性。
//原子性、可见性(修改立即更新到内存)、有序性
    private static volatile Singleton instance;

    // 3、向外暴露一个静态的公共方法,加入同步处理的代码块,并进行双重判断,解决线程安全问题
    public static Singleton getInstance() {
        if (instance == null) {    //第一次检查,可能有多个线程同时通过检查
//类级别的锁对象,锁对象是全局的,对该类的所有实例均有效。回顾锁对象是this时仅限于锁当前实例
            synchronized (Singleton.class) {    
                if (instance == null) {   //第二次检查,只会有1个线程通过检查并创建实例
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

Ventajas y desventajas

  • 1) El concepto de doble verificación se usa a menudo en el desarrollo de subprocesos múltiples. Hemos verificado dos veces para garantizar la seguridad de los subprocesos.
  • 2) De esta manera, el código de creación de instancias solo necesita ejecutarse una vez, y el objeto de creación de instancias se devuelve directamente cuando se vuelve a acceder a él más tarde, y también se evita la sincronización repetida de métodos.
  • 3) Seguridad del hilo; carga lenta; mayor eficiencia
  • 4) Conclusión: en el desarrollo real, se recomienda utilizar este patrón de diseño singleton

2.2.7 Clase interna estática (recomendado)

Subproceso seguro, carga diferida, alta eficiencia, recomendado. 

paso: 

  • 1) Privatización de constructores
  • 2) Defina una clase interna estática que defina internamente las propiedades estáticas de la clase actual
  • 3) Exponer un método público estático al exterior

Estación de servicio del conocimiento:

  1. El mecanismo de carga de clases es lazy loading, es decir, solo se cargará cuando se necesite una clase.
  2. Durante el proceso de carga de clases, todos sus miembros estáticos se cargarán en la memoria, incluidas las variables estáticas, los métodos de miembros estáticos y las clases internas estáticas.
  3. La carga de clases incluye carga, vinculación (verificación, preparación (asignación de memoria para variables de clase y asignación de valores cero), análisis), inicialización (asignación de valores iniciales a variables de clase, ejecución de bloques de declaraciones estáticas).
public class Singleton {
    // 1、构造器私有化
    private Singleton() {
    }

    // 2、定义一个静态内部类,内部定义当前类的静态属性
    private static class SingletonInstance {
        private static final Singleton instance = new Singleton();
    }

    // 3、向外暴露一个静态的公共方法
    public static Singleton getInstance() {
        return SingletonInstance.instance;
    }
}

Ventajas y desventajas

  • 1) Este método utiliza un mecanismo de carga de clases para garantizar que solo haya un subproceso al inicializar una instancia
  • 2) El método de clase interna estática no instancia la clase Singleton inmediatamente cuando se carga, sino que llama al método cuando necesita ser instanciado y luego carga la getlnstanceclase Singletonlnstance, completando así la instanciación de Singleton.
  • 3) Las propiedades estáticas de la clase solo se inicializarán cuando la clase se cargue por primera vez. La JVM nos ayuda a garantizar la seguridad del subproceso . Cuando la clase se inicializa, otros subprocesos no pueden ingresar.
  • 4) Ventajas: evite la inseguridad del subproceso, use características estáticas de clase interna para lograr una carga diferida, alta eficiencia
  • 5) Conclusión: Se recomienda utilizar

2.2.8 Enumeración (recomendado)

Recomendado, hilo seguro, carga diferida.

public enum Singleton {
    INSTANCE;

    public void sayHello() {
        System.out.println("Hello World");
    }
}
public class SingletonTest {
    public static void main(String[] args){
        Singleton instance = Singleton.INSTANCE;
        Singleton instance2 = Singleton.INSTANCE;
        System,out,println(instance == instance2);    //true
        System,out.println(instance.hashCode());
        System.out.println(instance2.hashCode());
    }
    public enum Singleton {
        INSTANCE;

        public void sayHello() {
            System.out.println("Hello World");
        }
    }
}

Ventajas y desventajas

  • 1) Esto implementa el patrón singleton con la ayuda de enumeraciones agregadas en JDK1.5. No solo puede evitar problemas de sincronización de subprocesos múltiples , sino que también evita que la deserialización recree nuevos objetos
  • 2) Este enfoque es defendido por Josh Bloch, autor de Java Eficaz.
  • 3) Conclusión: Se recomienda utilizar

2.2.9 Análisis del modo singleton en el código fuente de JDK

java.lang.Runtime en JDK es el patrón singleton clásico:

El estilo chino hambriento (variable estática) , definitivamente se utilizará, así que no tenga miedo de perder la memoria

Supongo que te gusta

Origin blog.csdn.net/qq_40991313/article/details/130423855
Recomendado
Clasificación