1. Singleton
* Propósito: Asegura que solo se cree una instancia de una clase y proporcione un punto de acceso global a esa instancia.
* Cuándo usar: Cuando necesite un recurso compartido único (por ejemplo, Administrador de configuración, grupo de conexión de base de datos, Logger).
* Ejemplo simple (Python):
`` `Python
Singleton de clase:
_instance =ninguno
def __new __ (CLS, *Args, ** Kwargs):
Si no es CLS._instance:
cls._instance =Super (Singleton, CLS) .__ New __ (CLS, *Args, ** Kwargs)
# Inicializar la instancia aquí si es necesario
return cls._instance
# Uso
instancia1 =singleton ()
instancia2 =singleton ()
print (instancia1 es instancia2) # salida:verdadero (son el mismo objeto)
`` `` ``
* Notas: Tenga cuidado con los singleton en entornos fuertemente multiproceso. Es posible que deba agregar mecanismos de bloqueo para garantizar la seguridad de los subprocesos durante la creación de instancias. El uso excesivo de singletons puede conducir a un acoplamiento ajustado y dificultar las pruebas.
2. Método de fábrica
* Propósito: Define una interfaz para crear un objeto, pero permite que las subclases decidan qué clase instanciar. Desacula el código del cliente de la clase específica que se está creando.
* Cuándo usar: Cuando necesita crear objetos de diferentes tipos basados en alguna condición o configuración, y desea evitar la codificación de la lógica de creación de objetos directamente en el código del cliente.
* Ejemplo simple (Python):
`` `Python
Botón de clase:
Def render (yo):
elevar NotisplementError ()
clase HTMLBUTTON (botón):
Def render (yo):
return "
clase WindowsButton (botón):
Def render (yo):
Devuelve "Botón de Windows (específico de la interfaz de usuario)"
clase ButtonFactory:
Def create_button (self, button_type):
if Button_type =="html":
return htmlButton ()
Elif button_type =="Windows":
Return WindowsButton ()
demás:
elevar ValueError ("Tipo de botón no válido")
# Uso
Factory =ButtonFactory ()
html_button =factory.create_button ("html")
Windows_Button =factory.create_button ("Windows")
print (html_button.render ()) # output:
print (windows_button.render ()) # Salida:botón de Windows (específico de la interfaz de usuario)
`` `` ``
* Notas: El método de fábrica le permite agregar nuevos tipos de botones sin modificar la clase 'ButtonFactory` directamente (principio abierto/cerrado).
3. Estrategia
* Propósito: Define una familia de algoritmos, encapsula cada uno y los hace intercambiables. La estrategia permite que el algoritmo varíe independientemente de los clientes que lo usan.
* Cuándo usar: Cuando tiene varias formas de realizar una tarea específica, y desea poder cambiar entre ellas fácilmente en tiempo de ejecución.
* Ejemplo simple (Python):
`` `Python
clase PaymentsTrategy:
Def PAGO (Self, Monte):
elevar NotisplementError ()
clase CreditCardPayment (PaymentStrategy):
def __init __ (self, card_number, expiry_date, cvv):
self.card_number =card_number
self.expiry_date =expiry_date
self.cvv =cvv
Def PAGO (Self, Monte):
imprime (f "pagando $ {cantidad} usando tarjeta de crédito:{self.card_number}")
clase PayPalPayment (PaymentsTrategy):
def __init __ (self, correo electrónico):
self.email =correo electrónico
Def PAGO (Self, Monte):
imprime (f "pagando $ {cantidad} usando paypal:{self.email}")
Clases de compras:
def __init __ (self, payment_strategy:paymentStrategy):# estrategia inyectada aquí
self.payment_strategy =payment_strategy
self.total =0
def add_item (self, precio):
self.total +=precio
DEF CABACIÓN (Self):
self.payment_strategy.pay (self.total)
# Uso
Credit_Card =CreditCardPayment ("1234-5678-9012-3456", "12/24", "123")
PayPal =PayPalpayment ("[email protected]")
CART1 =ShoppingCart (Credit_Card)
CART1.Add_Item (100)
CART1.Add_Item (50)
CART1.CHECKOUT () # Salida:Pagar $ 150 usando tarjeta de crédito:1234-5678-9012-3456
CART2 =ShoppingCart (PayPal)
CART2.Add_Item (200)
CART2.Checkout () # Salida:Pagar $ 200 usando PayPal:[email protected]
`` `` ``
* Notas: El `ShoppingCart` no necesita conocer el método de pago específico. Simplemente usa el `paymentstrategy 'inyectado para realizar el pago. Esto facilita agregar nuevos métodos de pago sin modificar la clase 'Shoppingcart'.
4. Observador
* Propósito: Define una dependencia de uno a muchos entre objetos para que cuando un objeto cambie de estado, todos sus dependientes se notifiquen y se actualizan automáticamente.
* Cuándo usar: Cuando un cambio en un objeto requiere cambiar otros objetos, y no desea que los objetos estén estrechamente acoplados. Ejemplos:manejo de eventos, actualizaciones de la interfaz de usuario, arquitectura del controlador de visión del modelo (MVC).
* Ejemplo simple (Python):
`` `Python
Asunto de la clase:
def __init __ (self):
self._observers =[]
Def Adjuntar (self, observador):
self._observers.append (observador)
Def separar (self, observador):
self._observers.remove (observador)
Def notificar (self, mensaje):
para observador en self._observers:
observador.update (mensaje)
Observador de clase:
AFT UPDATY (Self, Mensaje):
elevar NotisplementError ()
clase ConcreteBServera (Observador):
AFT UPDATY (Self, Mensaje):
print (f "Observador A recibido:{Mensaje}")
clase ConcreteBServerb (observador):
AFT UPDATY (Self, Mensaje):
print (f "Observador B Recibido:{Message.upper ()}")
# Uso
Sujeto =sujeto ()
Observer_a =ConcreteBSerVera ()
Observer_b =ConcreteBServerb ()
Sujeto.attach (Observer_a)
Sujeto.attach (observador_b)
Sujeto.notify ("¡Hola, mundo!") # Salida:Observador A recibido:¡Hola, mundo!
# Observador B Recibido:¡Hola, mundo!
Sujeto.detach (observador_a)
Sujeto.notify ("¡Adiós!") # Salida:Observador B Recibido:¡Adiós!
`` `` ``
* Notas: El `sujeto` mantiene una lista de 'observadores'. Cuando cambia el estado de 'sujeto' (en este caso, cuando se llama `notify`), se itera a través de la lista y llama al método` Última 'en cada' observador '.
5. Método de plantilla
* Propósito: Define el esqueleto de un algoritmo en una clase base, pero permite que las subclases anulen pasos específicos del algoritmo sin cambiar su estructura.
* Cuándo usar: Cuando tiene un conjunto de pasos que deben realizarse en un orden específico, pero algunos de esos pasos pueden variar según la implementación específica.
* Ejemplo simple (Python):
`` `Python
Class Dataprocessor:
Def process_data (self):
self.read_data ()
self.validate_data ()
self.transform_data ()
self.save_data ()
Imprimir ("Procesamiento de datos completo")
def read_data (self):
elevar NotisplementError ()
Def validate_data (self):
imprimir ("Validación predeterminada:verificación de valores nulos")
Def transform_data (self):
elevar NotisplementError ()
def save_data (self):
elevar NotisplementError ()
Clase CSVDATAPROCESOR (DataProcessor):
def read_data (self):
Imprimir ("Lectura de datos del archivo CSV").
Def transform_data (self):
Imprimir ("Transformando datos de CSV").
def save_data (self):
Imprimir ("Guardar datos en la base de datos").
clase JSondataprocessor (DataProcessor):
def read_data (self):
Imprimir ("Lectura de datos del archivo JSON").
Def validate_data (self):
Imprimir ("Validación personalizada para datos JSON:esquema de corriente").
Def transform_data (self):
Imprimir ("Transformando datos JSON").
def save_data (self):
Imprimir ("Guardar datos en el archivo JSON").
# Uso
csv_processor =csvdataprocessor ()
csv_processor.process_data ()
# Producción:
# Lectura de datos del archivo CSV.
# Validación predeterminada:verificación de valores nulos.
# Transformación de datos de CSV.
# Guardar datos en la base de datos.
# Procesamiento de datos completo.
json_processor =jSondataprocessor ()
json_processor.process_data ()
# Producción:
# Lectura de datos del archivo JSON.
# Validación personalizada para datos JSON:esquema de corriente.
# Transformando datos JSON.
# Guardar datos en el archivo JSON.
# Procesamiento de datos completo.
`` `` ``
* Notas: El `Dataprocessor` define la estructura general del algoritmo de procesamiento de datos. Las subclases como `csvdataprocessor` y` jsondataprocessor` proporcionan implementaciones específicas para los pasos `read_data`,` transform_data` y `save_data`. El paso `Validate_Data` se puede anular o usar la implementación predeterminada.
6. Decorador
* Propósito: Dinámicamente agrega responsabilidades a un objeto sin modificar su clase. Los decoradores proporcionan una alternativa flexible para la subclasificación para extender la funcionalidad.
* Cuándo usar: Cuando desea agregar funcionalidad a un objeto en tiempo de ejecución, sin afectar otros objetos de la misma clase. Útil para agregar registro, almacenamiento en caché o autorización.
* Ejemplo simple (Python):
`` `Python
Café de clase:
Def get_cost (self):
regresar 5
Def get_description (self):
Regrese "Café"
clase Coffeedecorator:
def __init __ (self, café):
self._coffee =café
Def get_cost (self):
return self._coffee.get_cost ()
Def get_description (self):
return self._coffee.get_description ()
clase MilkDecorator (Coffeedecorator):
Def get_cost (self):
return self._coffee.get_cost () + 2
Def get_description (self):
return self._coffee.get_description () + ", leche"
SUGARDECORADOR DE CLASE (COFFEDECORATOR):
Def get_cost (self):
return self._coffee.get_cost () + 1
Def get_description (self):
return self._coffee.get_description () + ", azúcar"
# Uso
café =café ()
print (f "{café.get_description ()} - costo:$ {café.get_cost ()}") # output:Coffee - Costo:$ 5
Milk_coffee =MilkDecorator (café)
print (f "{Milk_coffee.get_description ()} - Costo:$ {Milk_coffee.get_cost ()}") # Output:Coffee, Milk - Costo:$ 7
Sugar_milk_coffee =SugarDecorator (Milk_Coffee)
print (f "{Sugar_milk_coffee.get_description ()} - Costo:$ {Sugar_milk_coffee.get_cost ()}") # Salida:café, leche, azúcar - Costo:$ 8
`` `` ``
* Notas: El `Coffeedecorator` proporciona una clase base para los decoradores. Cada decorador (por ejemplo, `MilkDecorator`,` SugarDecorator`) envuelve el objeto 'Coffee` original y agrega su propia funcionalidad (en este caso, agregando costos y descripción).
Consideraciones clave para elegir un patrón:
* Comprender el problema: Defina claramente el problema que está tratando de resolver antes de buscar un patrón. No apliques a ciegas patrones; Úselos como herramientas para mejorar su código.
* Simplicidad: Comience con la solución más simple que satisface sus necesidades. No exagere las cosas prematuramente.
* contexto: El mejor patrón depende del contexto específico de su proyecto, el lenguaje que está utilizando y la base de código existente.
* Prueba: Los patrones de diseño deberían hacer que su código sea más comprobable, no menos. Asegúrese de poder escribir fácilmente pruebas unitarias para los componentes que está utilizando.
Estos son solo algunos ejemplos de patrones de diseño simples. A medida que obtenga más experiencia, aprenderá a reconocer situaciones en las que estos y otros patrones se pueden aplicar para crear un código más robusto, mantenible y reutilizable. ¡Buena suerte!