"Cada patrón
describe un problema que ocurre una y otra vez en nuestro entorno, y describe
la esencia de la solución a ese problema, de tal modo que pueda utilizarse esta
solución un millón de veces más, sin siquiera hacerlo de la misma manera dos
veces". Christopher Alexander (1977)
Para muchos diseñadores la reutilización de estructuras los convierte en
expertos, debido a que no se centran en buscar soluciones a cada problema si
estos han de seguir un patrón, es mejor darle solución con respuestas ya
encontradas y adaptándolas a un entorno en específico.
El Dictionary of Object Technology, 1995 define Patrón como “Una
arquitectura reusable que la experiencia ha mostrado que resuelve un problema
común en un contexto específico”
LOS PATRONES DE DE COMPORTAMIENTO
Son aquellos que están relacionados con algoritmos y con la asignación
de responsabilidades a los objetos.
Se entiende como algoritmo al "Conjunto ordenado y finito de operaciones que permite hallar la solución de un problema" Diccionario de la Real Academia Española (REA) 22° Edicion 2001
Ademas describen no solamente patrones de objetos o de clases, sino que
también engloban patrones de comunicación entre ellos. Al igual que los otros
tipos de patrones, se pueden clasificar en función de que trabajen con clases
(Template Method, Interpreter) u objetos (Chain of Responsability, Command,
Iterator, Mediator, Memento, Observer, State, Strategy, Visitor).
La variación de la encapsulación es la base de muchos patrones de
comportamiento. Cuando un aspecto de un programa cambia frecuentemente, estos patrones
trabajan con un objeto que encapsula dicho aspecto, teniendo que definir por
tanto, una clase abstracta que describe la encapsulación del objeto.
La solución más natural a
cierto tipo de problema común”. Viéndolo de ese modo, parece lógico pensar que
cuando nos topemos con uno de esos “problemas modelo” podríamos aplicar “la
solución conocida”, sin tener que reinventar la rueda” Bocanegra Juan 2013 (Modelo
de Programación)
A continuación se desarrollaran una serie de patrones que según su función trabajan orientados a objetos
ITERATOR (ITERADOR)
Provee una forma de
acceder secuencialmente a los elementos de una colección sin exponer su
representación interna. Los métodos que podemos definir en la
interfaz Iterador son: Primero(), Siguiente(), HayMas() y
ElementoActual().
Para la programación de C# (Actualización 11-2007),
Iterador es un método,
descriptor de acceso get u
operador que realiza una iteración personalizada sobre una matriz o clase de
colección utilizando la palabra clave yield. La instrucción de retorno yield hace
que un elemento de la secuencia de origen sea devuelto inmediatamente al
llamador antes de obtener acceso al elemento siguiente de la secuencia de
origen. Aunque un iterador se escribe como un método, el compilador lo traduce
en una clase anidada que es, en realidad, una máquina de estados. Esta clase
hace un seguimiento de la posición del iterador mientras continúe el bucle foreach del código cliente.
El
patrón iterator permite el acceso al contenido de una estructura sin exponer su
representación interna. Además diferentes iteradores pueden presentar
diferentes tipos de recorrido sobre la estructura (recorrido de principio a
fin, recorrido con saltos...). Por otro lado los iteradores no tienen por qué
limitarse a recorrer la estructura, sino que podrían incorporar otro tipo de
lógica (por ejemplo, filtrado de elementos). Es más, dados diferentes tipos de
estructuras, el patrón iterador permite recorrerlas todas utilizando una
interfaz común uniforme.
Entre las clase de iterador tenemos:
Iterador
flexible es utilizado para recorrer una estructura de datos. Por medio de este
iterador es posible consultar los diferentes elementos que hacen parte de una
estructura empezando desde el primer elemento de la misma. El iterador mantiene
el registro del progreso de recorrido de una estructura y puede indicar si aún
falta algún elemento por recorrer y de ser así consultarlo.
Iterador
simple es un objeto utilizado para recorrer una estructura de datos. Por medio
de un iterador simple es posible consultar los diferentes elementos que hacen
parte de una estructura empezando desde el primer elemento de la misma. El
iterador mantiene el registro del progreso de recorrido de una estructura y
puede indicar si aún falta algún elemento por recorrer y de ser así
consultarlo.
El
iterador simple tiene la posición del elemento que se va a visitar a continuación
(3), los elementos que se están recorriendo y la siguiente posición libre en
elementos. Corresponde en realidad al número de elementos sobre los que se está
iterando
La
diferencia entre el Iterador Simple y el Iterador Flexible es la manera que
esta implementada. La implementación de Iterador Simple se hace usando un
arreglo, mientras que la del Iterador Flexible se hace usando una lista
encadenada.
En conclusión!
La solución que propone el
patrón es añadir métodos que permitan recorrer la estructura sin referenciar
explícitamente su representación. La responsabilidad del recorrido se traslada
a un objeto iterador.
El problema de introducir
este objeto iterador reside en que los clientes necesitan conocer la estructura
para crear el iterador apropiado.
Esto se soluciona
generalizando los distintos iteradores en una abstracción y dotando a las
estructuras de datos de un método de fabricación que cree un iterador concreto.
MEDIATOR
(MEDIADOR)
Define un objeto que
encapsula la forma en la cual interactúan otros. Promueve el acoplamiento débil
Bocanegra J lo define como “Crea un objeto mediador que encapsula el cómo un conjunto
de objetos interactúan. Mediator promociona la organización de cómo interactúan
los objetos, sin necesidad de que entre ellos mismos se referencíen”
•
La comunicación entre los conjuntos de objetos está bien definido y es
complejo.
• Existen demasiadas relaciones y se necesita un punto común de
control o comunicación.
Consecuencias:
• Desacopla a los objetos: el patrón Mediator promueve bajar el acoplamiento entre objetos. Se puede variar y rehusar objetos y mediadores independientemente.
• Desacopla a los objetos: el patrón Mediator promueve bajar el acoplamiento entre objetos. Se puede variar y rehusar objetos y mediadores independientemente.
•
Simplifica la comunicación entre objetos: Los objetos que se comunican de la
forma "muchos a muchos" puede ser remplazada por una forma "uno
a muchos" que es menos compleja y más elegante. Además esta forma de
comunicación es más fácil de entender
•
Abstrae como los objetos cooperan: Haciendo a la mediación un concepto
independiente y encapsulándolo en un objeto permite enfocar como los objetos
interactúan. Esto ayuda a clarificar como los objetos se relacionan en un
sistema.
•
Centraliza el control: El mediador es el que se encarga de comunicar a los
objetos, este puede ser muy complejo, difícil de entender y modificar
Ejemplo
MEMENTO (RECUERDO)
Sin
violar el principio de encapsulación, captura y externaliza el estado interno
de un objeto de manera que el objeto pueda regresar al estado después.
Su
finalidad es almacenar el estado de un objeto (o del sistema completo) en un
momento dado de manera que se pueda restaurar en ese punto de manera sencilla.
Este patrón puede ser utilizado cuando
- El estado interno de un objeto debe ser guardado y restaurado en un momento posterior.
- El estado interno no se puede exponer mediante interfaces sin exponer la implementación.
MOTIVACION
Muchas
veces es necesario guardar el estado interno de un objeto. Esto debido a que
tiempo después, se necesita restaurar el estado del objeto, al que previamente
se ha guardado. Consideremos por ejemplo
una aplicación de composición de figuras geométricas, donde el usuario hace
sucesivas modificaciones a una composición, graficando nuevas líneas, círculos
y rectángulos.
Después
de cierto tiempo, el usuario logra una composición “casi perfecta”, pero decide
alcanzar la perfección, así que pinta una línea y esta no le sale como él esperaba.
Definitivamente el usuario quisiera regresar al instante en que su “creación”
era una obra de arte. Para dar solución a este problema, antes de que el
usuario agregue una nueva figura geométrica a la composición, se debería
guardar el estado de la composición y entonces siempre se tendría la
posibilidad de regresar hacia atrás y restaurar la composición a su estado
anterior.
PARTICIPANTES
- Memento: almacena el estado interno de un objeto Originator. El Memento puede almacenar mucho o parte del estado interno de Originator. Tiene dos interfaces. Una para Caretaker, que le permite manipular el Memento únicamente para pasarlo a otros objetos. La otra interfaz sirve para que Originator pueda almacenar/restaurar su estado interno, sólo Originator puede acceder a esta interfaz, al menos en teoría.
- Originator: crea un objeto Memento conteniendo una fotografía de su estado interno. Adicional usa a Memento para restaurar su estado interno
- Caretaker: es responsable por mantener a salvo a Memento. No opera o examina el contenido de Memento
CONSECUENCIAS
- Originator crea un Memento y el mismo almacena su estado interno, de esta manera no es necesario exponer el estado interno como atributos de acceso público, preservando así la encapsulación.
- Si Originator tendría que de almacenar y mantener a salvo una o muchas copias de su estado interno, sus responsabilidades crecerían y serían más complejas, se desviaría de su propósito disminuyendo la coherencia. Usar Mementos hace que Originator sea mucho más sencillo y coherente.
- El uso frecuente de Mementos para almacenar estados internos de gran tamaño, podría resultar costoso y perjudicar el rendimiento del sistema.
- Caretaker al no conocer detalles del estado interno de Originator, no tiene idea de cuánto espacio y tiempo se necesita para almacenar el estado interno de Originator en un Memento y restaurar su estado interno a partir de un Memento. Por lo que no puede hacer predicciones de tiempo ni de espacio.
OBSERVER (OBSERVADOR)
Define
una dependencia de uno a muchos de tal manera que cuando uno de ellos cambia,
todos los que dependen de él son notificados y actualizados automáticamente
Usa el patrón:
- Cuando una abstracción tiene dos aspectos, y uno depende del otro. Encapsular los aspectos en objetos distintos permite cambiarlos y reutilizarlos.
- Cuando cambiar un objeto implica cambiar otros, pero no sabemos exactamente cuántos hay que cambiar
- Cuando un objeto debe ser capaz de notificar algo a otros sin hacer suposiciones sobre quiénes son dichos objetos. Esto es, cuando se quiere bajo acoplamiento.
Por tanto, la razón de ser de este patrón es
desacoplar las clases de los objetos, aumentando la modularidad del lenguaje y
evitando bucles de actualización. La idea básica del patrón es que el
objeto de datos (o sujeto) contenga atributos mediante los cuales cualquier
objeto observador (o vista) se pueda suscribir a él pasándole una referencia a
sí mismo. De este modo, el sujeto mantiene así una lista de las referencias a
sus observadores.
Las clases de participantes en el esquema general de
este patrón de comportamiento son:
- Subject: Es el que conoce a sus observadores,
proporcionando una Interfaz para que se suscriban los objetos de
tipo Observer.
- Observer: Define la interfaz para actualizar los
objetos a los que se deben notificar los cambios en el objeto Subject.
- Concrete Subject: Guarda el estado de interés
para los objetos ConcreteObserver y envia una notificación a sus observadores
cuando cambia su estado.
- Concrete Observer: Mantiene una
referencia a un objeto Concrete Subject, guardando el estado que debería
permanecer sincronizado con el objeto observado, además de implementar la
interfaz Observer para mantener su estado consistente con el objeto observado
STATE (ESTADO)
Permite
que un objeto cambie su comportamiento al cambiar su estado. El objeto parecerá
que cambio de clase. Se utiliza cuando el comportamiento de un objeto cambia dependiendo
del estado del mismo.
Ejemplo:
Una
alarma puede tener diferentes estados: desactivada, activada, en configuración,
etc. En este caso se puede definir una interfaz Estado_Alarma, y luego definir
los diferentes estados Este patrón puede ser utilizado cuando se permite a un
objeto alterar su comportamiento según el estado interno en que se encuentre.
Participantes
- Context(Contexto): Este integrante define la interfaz con el cliente. Mantiene una instancia de ConcreteState (Estado Concreto) que define su estado actual
- State (Estado):Define una interfaz para el encapsulamiento de la responsabilidades asociadas con un estado particular de Context.
- Subclase ConcreteState:Cada una de estas subclases implementa el comportamiento o responsabilidad de Context.
El Contexto (Context)
delega el estado específico al objeto ConcreteState actual Un objeto Context
puede pasarse a sí mismo como parámetro hacia un objeto State. De esta manera
la clase State puede acceder al contexto si fuese necesario. Context es la
interfaz principal para el cliente. El cliente puede configurar un contexto con
los objetos State. Una vez hecho esto, los clientes no tendrán que tratar con
los objetos State directamente. Tanto el objeto Context como los objetos de
ConcreteState pueden decidir el cambio de estado.
Es bueno resaltar que este patrón hace los cambios de estado explícitos puesto que en otros tipos de
implementación los estados se cambian modificando valores en variables,
mientras que aquí al estar representado cada estado. Adicional facilita la ampliación
de estados. Cabe destacar que pueden ser
compartidos si no contienen variables de instancia, esto se puede lograr si el
estado que representan está enteramente codificado en su tipo. Cuando se hace
esto estos estados son Flyweights sin estado intrínseco.