Patrones de Diseño: Guía Completa y Ejemplos Prácticos

Los patrones de diseño son soluciones reutilizables a problemas comunes en el diseño de software. A continuación, se presenta una descripción de los patrones más utilizados:

Patrones de Creación

Factoría Abstracta

Proporciona una interfaz para crear familias de objetos relacionados o dependientes entre sí, sin especificar sus clases concretas.

  • Aplicación: Aconsejado cuando se prevé la inclusión de nuevas familias de productos.
  • Contra: Puede resultar contraproducente cuando se añaden nuevos productos o cambian los existentes, ya que afectaría a todas las familias creadas.
  • Consecuencias: Aísla las clases concretas, facilita el intercambio de familias de productos, promueve la consistencia entre productos, pero dificulta dar cabida a nuevos tipos de productos.

Builder

Separa la construcción de un objeto complejo de su representación, de forma que el mismo proceso de construcción pueda crear diferentes representaciones del objeto.

  • Aplicación: Útil cuando el algoritmo para crear el objeto debe ser independiente de las partes que lo componen.
  • Contra: Permite variar la representación interna del producto, aísla el código de construcción y representación, proporciona un control más fino sobre el proceso de construcción.

Factoría

Define una interfaz para crear un objeto, pero deja que sean las subclases quienes decidan qué clase instanciar. Permite que una clase delegue en sus subclases la creación de objetos.

  • Aplicación: Cuando una clase no puede prever la clase de objetos que debe crear, o una clase quiere que sean sus subclases quienes especifiquen los objetos que esta crea.
  • Contra: Los métodos de fábrica eliminan la necesidad de ligar clases específicas a la aplicación de nuestro código. Un inconveniente potencial es que los clientes pueden tener que heredar de la clase creador simplemente para crear un determinado objeto ProductoConcreto, introduciendo una nueva vía de futuros cambios.

Prototype

Especifica el tipo de objetos a crear usando una instancia prototípica y creando nuevos objetos mediante la copia de este prototipo.

  • Aplicación: Cuando las clases a instanciar son especificadas en tiempo de ejecución, para evitar una jerarquía de clases de fábricas paralela a la jerarquía de clases de los productos.
  • Contra: Permite añadir y eliminar productos en tiempo de ejecución, especificar nuevos objetos modificando valores, y reduce la herencia.

Singleton

Garantiza que una clase solo tenga una instancia y proporciona un punto de acceso a ella.

  • Aplicación: Cuando la instancia debería ser extensible mediante herencia y los clientes deberían ser capaces de usar una instancia extendida sin modificar su código.
  • Contra: Acceso controlado a una única instancia, espacio de nombres reducido, más flexible que las operaciones de clase.

Patrones Estructurales

Adapter

Convierte la interfaz de una clase en otra interfaz que es la que esperan los clientes. Permite que cooperen clases que de otra forma no podrían por tener interfaces incompatibles.

  • Aplicación: Cuando se quiere usar una clase existente y su interfaz no concuerda con la que se necesita.
  • Contra: Permite que el adaptador redefina parte del comportamiento de adaptable, introduce un solo objeto y no se necesita ningún puntero de indirección adicional para obtener el objeto adaptado.

Bridge

Desacopla una abstracción de su implementación, de modo que ambas puedan variar de forma independiente.

  • Aplicación: Evitar un enlace permanente entre una abstracción y su implementación.
  • Contra: Desacopla la interfaz y la implementación, mejora la extensibilidad, oculta detalles de implementación a los clientes.

Composite

Compone objetos en estructuras de árbol para representar jerarquías de parte-todo. Permite que se traten de manera uniforme objetos individuales y compuestos.

  • Aplicación: Cuando se quiera obviar diferencias entre composiciones de objetos y objetos individuales.
  • Contra: Simplifica el cliente, facilita añadir nuevos tipos de componentes, puede hacer que un diseño sea demasiado general.

Decorator

Asigna responsabilidades a un objeto dinámicamente, proporcionando una alternativa flexible a la herencia para extender la funcionalidad.

  • Aplicación: Añadir objetos de forma dinámica y transparente, para responsabilidades que pueden ser retiradas, cuando la extensión mediante herencia no es viable.
  • Contra: Más flexibilidad que la herencia estática, evita clases cargadas de funciones en la parte superior de la jerarquía, un decorador y un componente no son idénticos, muchos objetos pequeños.

Flyweight

Usa compartimiento para permitir un gran número de objetos de grano fino de forma eficiente. Describe cómo compartir objetos para permitir su uso con granularidades muy finas sin un coste prohibitivo. Es un objeto compartido que puede usarse a la vez en varios contextos.

  • Aplicación: La app usa un gran número de objetos, costes de almacenamiento son elevados debido a tantos objetos.
  • Contra: Pueden introducir costes en tiempo de ejecución con la transferencia, búsqueda y cálculo del estado, sin embargo, estos costes pueden verse compensados por el ahorro de espacio de almacenamiento.

Proxy

Proporciona un representante o sustituto de otro objeto para controlar el acceso a este.

  • Aplicación: Cuando hay una necesidad de una referencia a un objeto más versátil o sofisticada que un simple puntero. Tipos: remoto, virtual, protección.
  • Contra: Puede ocultar el hecho de que un objeto reside en un espacio de direcciones distinto, puede llevar a cabo optimizaciones tales como crear un objeto por encargo.

Patrones de Comportamiento

Chain of Responsibility

Evita acoplar el emisor de una petición a su receptor, dando a más de un objeto la posibilidad de responder a la petición. Encadena los objetos receptores y pasa la petición a través de la cadena hasta que es procesada por algún objeto.

  • Aplicación: Cuando hay más de un objeto que puede manejar una petición y el manejador no se conoce a priori.
  • Contra: Reduce el acoplamiento, añade flexibilidad para asignar responsabilidades a otros objetos, no se garantiza la recepción.

Command

Encapsula una petición en un objeto, permitiendo así parametrizar a los clientes con diferentes peticiones, hacer cola o llevar un registro de las peticiones o poder deshacer las operaciones.

  • Aplicación: Especificar, poner en cola y ejecutar peticiones en distintos instantes de tiempo, permitir deshacer, permitir registrar cambios de manera que se puede volver a aplicar en caso de caída del sistema.
  • Contra: Órdenes son objetos de primera clase, se pueden ensamblar órdenes en una orden compuesta, fácil añadir nuevas órdenes.

Interpreter

Dado un lenguaje, define una representación de su gramática junto con un intérprete que usa dicha representación para interpretar sentencias del lenguaje.

  • Aplicación: Cuando hay un lenguaje que interpretar y se pueden representar las sentencias como árboles sintácticos abstractos.
  • Contra: Fácil cambiar y ampliar la gramática, fácil implementar la gramática, gramáticas complejas fáciles de mantener.

Iterator

Proporciona un modo de acceder secuencialmente a los elementos de un objeto agregado sin exponer su representación interna.

  • Aplicación: Permitir varios recorridos, proporciona interfaz uniforme para hacer recorridos.

Mediator

Define un objeto que encapsula cómo interactúan una serie de objetos. Promueve un bajo acoplamiento al evitar que los objetos se refieran unos a otros explícitamente y permite variar la interacción entre ellos de forma independiente.

  • Aplicación: Cuando un conjunto de objetos se comunican de forma definida pero compleja.
  • Contra: Reduce la herencia, simplifica los protocolos de los objetos, abstrae cómo cooperan los objetos, centraliza el control.

Memento

Representa y externaliza el estado interno de un objeto sin violar la encapsulación, de forma que este puede volver a dicho estado más tarde.

  • Contra: Preservación de los límites de encapsulación, uso de memoria puede ser costoso, definición de interfaces reducidas y amplias, costes ocultos en el cuidado de los mementos.

Strategy

Define una familia de algoritmos, encapsula cada uno de ellos y los hace intercambiables. Permite que un algoritmo varíe independientemente de los clientes que lo usan.

  • Aplicación: Cuando muchas clases relacionadas difieren solo en su comportamiento, se necesitan distintas variantes del algoritmo, un algoritmo usa datos que los clientes no deberían conocer.
  • Contra: Se eliminan sentencias condicionales, los clientes deben conocer las distintas implementaciones, mayor número de objetos.

Template

Define en una operación el esqueleto de un algoritmo, delegando en las subclases algunos de sus pasos. Permite que las subclases redefinan ciertos pasos de un algoritmo sin cambiar su estructura.

  • Aplicación: Implementar las partes de un algoritmo que no cambian y dejar que sean las subclases quienes implementen el comportamiento que puede variar.
  • Contra: Técnica fundamental de reutilización de código, particularmente importantes en bibliotecas de clases, son el modo de factorizar y extraer el comportamiento común de las clases de la biblioteca.

Visitor

Representa una operación sobre los elementos de una estructura de objetos. Permite definir una nueva operación sin cambiar las clases de los elementos sobre los que opera.

  • Aplicación: Una estructura de objetos contiene muchas clases de objetos con diferentes interfaces y queremos realizar operaciones sobre esos elementos que dependen de su clase concreta.
  • Contra: Facilita añadir nuevas operaciones, un visitante agrupa operaciones relacionadas y separa las que no lo están, acumular el estado, romper la encapsulación.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.