3.1 Único

Singleton es un patrón de diseño genérico que garantiza que una aplicación de subproceso único tendrá una única instancia de alguna clase y proporciona un punto de acceso global a esta instancia.

único

Muy a menudo, a los programadores novatos les gusta ensamblar métodos de utilidad en alguna clase estática, una clase que contiene solo métodos estáticos. Este enfoque tiene una serie de desventajas: por ejemplo, no puede pasar una referencia a un objeto de dicha clase, dichos métodos son difíciles de probar y similares.

Como alternativa, se propuso una solución de clase singleton: una clase que solo puede tener un objeto. Al intentar crear este objeto, solo se crea si aún no existe; de ​​lo contrario, se devuelve una referencia a una instancia ya existente.

Es esencial que sea posible utilizar una instancia de la clase, ya que en muchos casos se dispone de una funcionalidad más amplia. Por ejemplo, esta clase puede implementar algunas interfaces y su objeto puede pasarse a otros métodos como una implementación de la interfaz. Lo que no se puede hacer con un conjunto de métodos estáticos.

Ventajas:

  • Los métodos están vinculados a un objeto, no a una clase estática: puede pasar un objeto por referencia.
  • Los métodos de objetos son mucho más fáciles de probar y simular.
  • Un objeto solo se crea cuando es necesario: inicialización de objeto perezoso.
  • Acelerar el lanzamiento inicial del programa si hay muchos sencillos que no se necesitan para el lanzamiento.
  • Solo se puede convertir en una estrategia de plantilla o en varios de estos objetos.

Contras:

  • Se vuelve más difícil controlar las carreras y los retrasos entre subprocesos.
  • Es difícil escribir un "solitario" de múltiples subprocesos "desde la cabeza": el acceso a un singleton de larga data, idealmente, no debería abrir un mutex. Mejores soluciones probadas.
  • Un conflicto entre dos subprocesos sobre un único subproceso inacabado provocará un retraso.
  • Si el objeto se crea durante mucho tiempo, la demora puede interferir con el usuario o interrumpir el tiempo real. En este caso, es mejor transferir su creación a la etapa de inicialización del programa.
  • Se requieren características especiales para las pruebas unitarias, por ejemplo, para poner la biblioteca en modo "no solitario" y aislar completamente las pruebas entre sí.
  • Se requiere una táctica especial para probar el programa terminado, porque incluso el concepto de "la capacidad de lanzamiento más simple" desaparece, porque la capacidad de lanzamiento depende de la configuración.

3.2 Fábrica [Método]

Un método de fábrica es un patrón de diseño genérico que proporciona subclases (clases-herederas) con una interfaz para crear instancias de una determinada clase. En el momento de la creación, los descendientes pueden determinar qué clase crear.

En otras palabras, esta plantilla delega la creación de objetos a los descendientes de la clase principal. Esto le permite usar clases no concretas en el código del programa, sino manipular objetos abstractos en un nivel superior.

Método de fábrica

Este patrón define una interfaz para crear un objeto, pero deja que las subclases decidan en qué clase basar el objeto. Un método de fábrica permite que una clase delegue la creación de subclases. Se usa cuando:

  • la clase no sabe de antemano qué objetos de qué subclases necesita crear.
  • una clase está diseñada para que los objetos que crea estén especificados por subclases.
  • la clase delega sus responsabilidades a una de varias subclases auxiliares, y se planea determinar qué clase asume estas responsabilidades.

3.3 Fábrica abstracta

Una fábrica abstracta es un patrón de diseño genérico que proporciona una interfaz para crear familias de objetos relacionados o interdependientes sin especificar sus clases concretas.

El patrón se implementa creando una clase abstracta Factory, que es una interfaz para crear componentes del sistema (por ejemplo, para una interfaz de ventana, puede crear ventanas y botones). Luego se escriben clases que implementan esta interfaz.

Fábrica abstracta

Se utiliza en los casos en que el programa debe ser independiente del proceso y tipos de nuevos objetos creados. Cuando sea necesario crear familias o grupos de objetos relacionados, excluyendo la posibilidad de uso simultáneo de objetos de diferentes conjuntos de estos en un mismo contexto.

Fortalezas:

  • aísla clases específicas;
  • simplifica la sustitución de familias de productos;
  • garantiza la compatibilidad del producto.

Digamos que su programa funciona con el sistema de archivos. Luego, para trabajar en Linux, necesita los objetos LinuxFile, LinuxDirectory, LinuxFileSystem. Y para trabajar en Windwos, necesita las clases WindowsFile, WindowsDirectory, WindowsFileSystem.

La clase Path, que se crea a través de Path.of(), es solo un caso así. Path no es realmente una clase, sino una interfaz, y tiene implementaciones de WindowsPath y LinuxPath. Y qué tipo de objeto se creará está oculto en su código y se decidirá en tiempo de ejecución.

3.4 Prototipo

El prototipo es un patrón de diseño generativo.

Este patrón define los tipos de objetos que se crean utilizando una instancia de prototipo y crea nuevos objetos copiando este prototipo. Le permite alejarse de la implementación y seguir el principio de "programación a través de interfaces".

Una interfaz/clase abstracta en la parte superior de la jerarquía se especifica como el tipo de retorno, y las clases descendientes pueden sustituir a un heredero que implemente este tipo allí. En pocas palabras, este es el patrón de crear un objeto mediante la clonación de otro objeto en lugar de crearlo a través de un constructor.

Prototipo

El patrón se utiliza para:

  • evitando el esfuerzo adicional de crear un objeto de forma estándar (es decir, usando un constructor, ya que en este caso también se llamará a los constructores de toda la jerarquía de ancestros del objeto), cuando esto es prohibitivamente costoso para la aplicación.
  • evite heredar el creador del objeto en la aplicación cliente, como lo hace el patrón de fábrica abstracto.

Utilice este patrón de diseño cuando a su programa no le importe cómo crea, compone y presenta productos:

  • las clases instanciadas se determinan en tiempo de ejecución, por ejemplo, mediante carga dinámica;
  • quiere evitar construir jerarquías de clases o fábricas que sean paralelas a la jerarquía de clases de productos;
  • las instancias de clase pueden estar en uno de varios estados diferentes. Puede ser más conveniente establecer el número apropiado de prototipos y clonarlos, en lugar de instanciar manualmente la clase en el estado apropiado cada vez.