31
Oct

Patrones de Diseño

¿Que es un patrón de diseño?

Es una descripción de objetos y clases comunicándose entre sí, que se personalizan para resolver un problema general del diseño de software en un contexto particular.
La descripción de la solución sl problema general se realiza en términos de estructura  (clases, interfaces, relaciones) y comportamiento (interacciones entre objetos).

Singleton

Problema: ¿Comó asegurar que una clase tenga una única instancia accesible globalmente?
Aplicabilidad: Utilice Singleton cuando una clase deba tener una única instancia globalmente accesible para cualquie cliente.
Estructura:
Comportamiento:
Consecuencias:
  • Permite el acceso controlado a una instancia.
  • Fácilmente modificable para permitir un conjunto de instancias.

Composite

Problema: ¿Cómo tratar objetos que pueden ser compuestos de otros objetos como si fueran objetos individuales?
Aplicabilidad:
  • Representar jerarquías de objetos compuestos de otros objetos así como de objetos individuales.
  • Los clientes ignoran las diferencias entre objetos individuales y objetos compuestos dentro de esa jerarquía y los manipulan indistintamente.
Estructura:
Consecuencias:
  • Fácil introducción de nuevos tipos de componentes sin modificar código cliente existente.
  • Los clientes son sencillos: evita lógica condicional en ellos y manipulan de igual forma los componentes.
  • Generalidad VS Control: el hecho de que los componentes sean tratados genéricamente (lo cual es una ventaja para el cliente) también presenta una desventaja en cuanto no poder controlar el tipo de elementos de un compuesto (ej: si se tienen dos tipos de hojas y se necesita que determinado elemento compuesto sólo tenga un tipo de hoja).

Proxy

Problema: ¿Cómo impedir el acceso directo a un objeto?
Aplicabilidad:
  • Remote Proxy: provee un representante local para un objeto que se encuentra en otra ubicación.
  • Virtual Proxy: crea objetos “caros” a demanda.
  • Protection Proxy: controla el acceso al objeto original.
Estructura:
Consecuencias:
  • Introduce un nivel de indirección, cuya utilidad depende de la variante utilizada:
    • Remote Proxy: oculta el hecho que el objeto real se encuentra en una ubicación remota.
    • Virtual Proxy: realiza optimizaciones como crear un objeto a demanda en lugar de tenerlo instanciado siempre.
    • Protection Proxy: permite tareas de control y mantenimiento cada vez que el objeto real es accedido.
  • En los casos donde el Proxy no deba instanciar el objeto real, podría conocerlo a través de una interfaz.

Adapter

Problema: ¿Cómo hacer interactuar una clase ya creada con otra cuya interfaz cambió?
Aplicabilidad:
  • Si la clase A utiliza la clase B y los servicios que brinda B cambian, A se verá afectada y también deberá cambiar, a menos que se introduzca una clase X que se adapte al uso de A pero conociendo la nueva B.
    Es decir que se pasa de A > B a tener A > X > B
  • Resolver incompatibilidad de interfaces.
Estructura:
Consecuencias:
  • Un adaptador puede cambiar su clase de destino dinámicamente.
  • Un adaptador puede simplemente adaptar el nombre de una operación hasta adaptar toda una interfaz completa, incluyendo los parametros.
  • Generalmente el objeto adaptado ya no puede ser utilizado mediante su vieja interfaz (a menos que el adapter tambien lo permita).

Template Method

Problema: Definir el esqueleto de un algoritmo en una operación, relegando algunos pasos a subclases. Las subclases redifinirian ciertos pasos del algoritmo sin cambiar su estructura.
Aplicabilidad:
  • Implementar las partes invariantes de un algoritmo una única vez y delegar los pasos variables a subclases.
  • Para factorizar comportamiento común de subclases en una nueva clase abstracta.
Estructura:
Consecuencias:
  • Es importante diferenciar aquellas operaciones utilizados por los templates method que deban ser reddefinidas (que serán abstractas en la super clase) de las que puedan ser redefinidas (que serán concretas en la super clase).
  • El template method no debera ser redefinido.
  • Cuantas más operaciones abstractas se definan en la clase abstracta, más trabajo deberán realizar las clases concretas.

Observer

Problema: Definir una dependencia “uno a muchos” entre objetos de tal forma que cuando el “uno” cambie, los “muchos” sean notificados.
Aplicabilidad:
  • Cuando un elemento tenga dos aspectos, uno dependiente del otro, y encapsularlos en objetos diferentes permite modificarlos y reutilizarlos independientemente.
  • Cuando cambios en un objeto requieran cambios en otros objetos, y no se sabe cuántos de éstos últimos serán.
  • Cuando un objeto deba notificar a otros sin acoplarse a éstos.
Estructura:
Consecuencias:
  • El Subject puede separarse en dos: una clase abstracta Subject con operaciones de attach, detach y notifyAll (ya predefinidas) y una subclase ConcreteSubject que representa el tipo de objeto que será observado.
  • En la estructura se mostró que el Subject posee un método ( operación() ) el cual desencadena el cambio de estado, por lo que deberá invocar a notifyAll() el cual fue declarado como privado. Sin embargo, no tienen porqué ser dos métodos diferentes.
  • La operación notify() puede enviar parámetros que contengan información sobre el cambio ocurrido en el Subject.
  • Generalmente son los propios observadores los que cambian el estado del Subject (en este caso invocando operacion() ).
  • Para que un objeto sea notificado:
    1. Su clase debe implementar la interfaz Observer
    2. El objeto debe registrarse ante el Subject

State

Problema: Permitir a un objeto alterar su comportamiento cuando su estado interno cambie. El objeto parecerá haber cambiado de clase.
Aplicabilidad:
  • Cuando el comportamiento de un objeto dependa de su estado y debe cambiar su comportamiento en tiempo de ejecución dependiendo de ese estado.
  • Cuando las operaciones contengan sentencias condicionales que dependan del estado del objeto.
Estructura:
Consecuencias:
  • El patrón State representa el estado como un objeto por sí mismo, con una subclase por cada estado posible del objeto.
  • Los cambios de estado pueden ser manejados ya sea por los propios estados o bien por el Context.
  • Si los cambios los manejan los propios estados, entonces el Diagrama de Clases debe modificarse colocándose las dependencias entre estados que correspondan.
  • El Context puede enviar información mediante parametros de oper() o bien enviarselos a si mismo para que los estados puedan consultar información.
  • El patrón State puede combinarse con Singleton para hacer que los estados concretos tengan una unica instancia.
  • Agregar nuevos tipos de estados concretos tiene un bajo impacto, pues únicamente implica que alguien debe devolver ese nuevo estado concreto.
  • Se puede utilizar un Diagrama de Estados para representar como es la lógica de cambio de estado del objeto.
  • En caso de no ser apropiado que oper() retorne el nuevo estado entonces el Context puede proveer una operación pública de cambio de estado.

Strategy

Problema: Definir una familia de algoritmos, encapsular cada uno de ellos en una clase y hacerlos intercambiables. Strategy permite variar el algoritmo independientemente de los clientes que lo utilicen.
Aplicabilidad:
  • Cuando muchas clases relacionadas difieran sólo en su comportamiento.
  • Cuando necesite diferentes diferentes variantes de un algoritmo.
  • Cuando una clase contenga diferentes comportamientos mediante sentencias condicionales.
Estructura:
Consecuencias:
  • El Context puede enviar información mediante parámetros o bien eviarse a sí mismo para que las estrategias concretas puedan consultar información.
  • El Cliente tiene a su disposición una familia de algoritmos de la cual elegir una para crear el Context, luego de lo cual el Cliente sólo interectuará con éste.
  • La estrategia concreta puede cambiarse dinamicamente.
  • El Cliente conoce las estrategias concretas y selecciona una para su utilización. Esto significa que Strategy debe utilizarse cuando este acoplamiento sea aceptable.
  • Las estrategias concretas pueden ser Singleton y ser compartidas por todos los Context.
  • Opcionalmente, el Context puede contener una implementación por defecto del algoritmo, con lo que permitiría su uso aún sin haber creado ninguna estrategia concreta.