Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ADAPTADOR / ADAPTER...............................................................................................................................6
ESTADO / STATE............................................................................................................................................21
FACHADA / FACADE.....................................................................................................................................26
INTÉRPRETE / INTERPRETER...................................................................................................................28
ITERADOR / ITERATOR...............................................................................................................................32
PROTOTIPO / PROTOTYPE.........................................................................................................................44
________________________________________________________________________________
-i-
SOLITARIO / SINGLETON ...........................................................................................................................50
VISITANTE / VISITOR...................................................................................................................................53
________________________________________________________________________________
- ii -
Colección de patrones Banda de los Cuatro
ACCIÓN / COMMAND
Tipo
Comportamiento, a nivel de objetos.
Problema
Uno de los elementos principales de una interfaz gráfica de usuario (GUI) son los menús
desplegables. En el interior de un menú se encuentran una serie de operaciones,
funciones o facilidades que una aplicación ofrece con relación a un tema en concreto
(Archivo, Edición, Ver, Insertar, Formato, etc...). Las distintas entradas de un menú tienen
la característica de que al ser “pinchadas” con el ratón o al ser seleccionadas mediante
teclado ejecutan una operación concreta. Un modelo de objetos que represente lo
anterior puede ser el siguiente:
ENTRADA_ABRIR
aplicación PedirNombre()
Seleccionar()
doc
DOCUMENTO
Abrir() nb=PedirNombre();
Cerrar() doc=new Documento(nb);
Copiar() aplicación->Añadir(doc);
doc->Abrir();
El siguiente escenario muestra como interactúan los objetos del modelo anterior:
new Entrada_Abrir(e_a)
Añadir(e_a)
Seleccionar()
new Documento(doc)
Añadir(doc)
Abrir()
________________________________________________________________________________
-1-
Colección de patrones Banda de los Cuatro
Otro elemento relevante de una GUI hoy en día son las barras de botones, al igual que,
en los comienzos de estas interfaces, también lo fueron, con una misión similar, las
combinaciones de teclas. En la mayoría de los casos, un botón sirve para ejecutar alguna
de las funciones más usuales de la aplicación, por lo cual coincide, en la función que
desempeña, con alguna entrada de algún menú. Al modelo de objetos anterior se le han
añadido en negrita las novedades necesarias para representar las barras de botones:
BARRA
Añadir(bot)
APLICACIÓ
N MENÚ ENTRADA
Añadir(doc) Añadir(entr) Seleccionar()
BOTÓN
Presionar()
ENTRADA_ABRIR
aplicación PedirNombre() doc
Seleccionar() BOTÓN_ABRIR
doc
PedirNombre()
Presionar()
DOCUMENTO
Abrir() nb=PedirNombre();
Cerrar() doc=new Documento(nb);
Copiar() aplicación->Añadir(doc);
doc->Abrir(); nb=PedirNombre();
doc=new Documento(nb);
aplicación->Añadir(doc);
aplicación doc->Abrir();
new Botón_Abrir(b_a)
Añadir(b_a)
Presionar()
new Documento(doc)
Añadir(doc)
Abrir()
________________________________________________________________________________
-2-
Colección de patrones Banda de los Cuatro
Una solución que nos permite evitar esa redundancia consiste en definir la acción que se
quiere ejecutar como un objeto, al cual pueden referirse todos aquellos elementos gráficos
que lo deseen. Aplicando esta idea tenemos la siguiente estructura:
ABRIR
aplicación BOTÓN
PedirNombre()
doc
Ejecutar() AsignarAcc()
Presionar()
DOCUMENTO nb=PedirNombre();
doc=new Documento(nb);
Abrir() aplicación->Añadir(doc);
Cerrar() acción->Ejecutar()
doc->Abrir();
Copiar()
new Abrir(acción)
AsignarAcc(acción)
AsignarAcc(acción)
Ejecutar()
Seleccionar()
new Documento(doc)
Añadir(doc)
Abrir()
Ejecutar()
Presionar()
new Documento(doc)
Añadir(doc)
Abrir()
Solución
________________________________________________________________________________
-3-
Colección de patrones Banda de los Cuatro
Contexto
La solución anterior es apropiada cuando lo fundamental en la relación entre una
petición y la acción que la satisface es la FLEXIBILIDAD. Este patrón, al encapsular en
un objeto la acción, promueve una separación entre dicha acción y la petición que
resuelve, lo cual redunda en una mayor flexibilidad en todo lo relativo a la acción. Esto
tiene las siguientes consecuencias:
✔ Diferentes objetos pueden ejecutar la misma acción sin necesidad de repetir su
declaración e implementación. Basta con que la “compartan”1.
✔ Se puede cambiar con facilidad (incluso dinámicamente) la acción que realiza o
está asociada a un objeto.
✔ Se pueden añadir nuevas acciones sin tocar las clases ya existentes2.
✔ Se puede especificar, encolar y ejecutar una acción en momentos diferentes3.
✔ Se puede contemplar la posibilidad de deshacer una operación. Para ello es
necesario disponer de una “lista de históricos” en la que se reflejen los diferentes estados
por los que pasa el sistema o el objeto afectado por las sucesivas operaciones. Igual que
se deshacen una o varias operaciones, se puede dar la posibilidad de volver a hacer
(“rehacer”) operaciones ya deshechas.
✔ Se pueden ensamblar acciones, para formar una acción compuesta
(macroacción). Esto puede resultar interesante en sistemas de información que dan
soporte a transacciones4.
Estructura
RECEPTOR
Ejecutar()
receptor -> Operación()
CLIENTE estado
Relacionado con
· Composición puede usarse para implementar “macroacciones”, es decir, Acciones
compuestas.
1
No se trata de compartir un objeto concreto, sino una clase, a través de instancias distintas de la misma.
2
Al representar las acciones como objetos “de pleno derecho” se da la posibilidad de modificarlas y/o
extenderlas, como al resto de los objetos, aplicando los mecanismos que para ello ofrece la teoría de objetos.
3
Como se ha separado la petición de la acción que la satisface, es posible que tengan un tiempo de vida
distinto, es decir, unas historias no necesariamente paralelas.
4
Una transacción encapsula una serie de cambios efectuados sobre unos datos. Este patrón sirve muy bien a
este interés, porque permite estructurar el sistema en base a acciones de alto nivel, que se constituyen a partir de
operaciones primitivas.
________________________________________________________________________________
-4-
Colección de patrones Banda de los Cuatro
· Recuerdo puede usarse para guardar el estado del sistema antes de que una
petición sea atendida y así poder luego deshacer el efecto de la Acción ejecutada.
· Una Acción de la que necesariamente debe hacerse copia antes de ser
introducida en la “lista de históricos” se comporta como un Prototipo.
________________________________________________________________________________
-5-
Colección de patrones Banda de los Cuatro
ADAPTADOR / ADAPTER
Tipo
Estructura, tanto a nivel de clases como a nivel de objetos.
Propósito
Convertir la interfaz de una clase para que se adapte a lo que el cliente que la usa
necesita, permitiendo así que trabajen juntas clases cuyas interfaces son incompatibles.
Estructura
ADAPTADOR
Petición()
PeticiónConcreta()
adaptado
ADAPTADOR
Petición()
adaptado->PeticiónConcreta()
Cuando usarlo
· Cuando se quiere usar una clase ya existente, pero su interfaz no encaja con lo
que se necesita.
· Cuando se quiere crear una clase reutilizable, para cooperar con otras clases que
no tengan, necesaria ni previsiblemente, interfaces compatibles.
· (sólo en la versión para objetos) Cuando se quieren usar varias subclases ya
existentes, pero no resulta práctico adaptarlas una a una mediante herencia. En vez de
esto, se puede adaptar la interfaz de la clase de la cual todas ellas heredan (y
especializan) su comportamiento.
Ventajas
A nivel de clases ...
________________________________________________________________________________
-6-
Colección de patrones Banda de los Cuatro
Inconvenientes
A nivel de clases ...
· Inflexibilidad, puesto que un sólo adaptador no puede trabajar con una clase y sus
hijos a la vez.
A nivel de objetos ...
· Dificultad para redefinir el comportamiento de la clase adaptada.
Relacionado con
· Puente tiene una estructura similar pese a ser su objetivo diferente (separar
interfaz de implementación).
· Decorador es más transparente dado que mejora un objeto sin cambiar su
interfaz.
· Apoderado define un “delegado” para un objeto sin tocar tampoco su interfaz.
Ejemplo de aplicación
En un editor gráfico de figuras lo fundamental es tener una abstracción que
represente la forma de cualquier elemento gráfico genérico. Para conformar elementos ya
existentes, nuevos o excesivamente complejos con la interfaz definida para esta forma
genérica podemos usar un adaptador (en este caso, a nivel de objetos).
texto
FORMA DE FORMA DE TEXTO
LÍNEA
Contorno() Contorno()
texto -> ObtenerExtensión()
APODERADO / PROXY
Tipo
________________________________________________________________________________
-7-
Colección de patrones Banda de los Cuatro
Propósito
Proporcionar un representante o delegado que se encargue de controlar el acceso
a un objeto, generalmente por motivos de eficiencia.
Estructura
ELEMENTO
CLIENTE
Petición()
Cuando usarlo
En cualquier situación en que sea necesaria una referencia a un objeto más versátil
y/o sofisticada que un simple puntero. Por ejemplo :
· Un apoderado remoto proporciona un representante local para un objeto en un
espacio de direcciones diferente (J.Coplien los llama embajadores).
· Un apoderado virtual crea por demanda objetos costosos.
· Un apoderado de protección restringe, por motivos de seguridad, el acceso a un
objeto.
· Una referencia “inteligente” es una sustitución por un simple puntero, que
incorpora servicios adicionales como cuenta del nº de referencias, carga de objetos
persistentes en memoria cuando estos son referenciados y uso de cerrojos para controlar
el acceso exclusivo a regiones críticas.
Ventajas
· Se introduce un nivel de indirección en el acceso al objeto, que permite al
apoderado remoto ocultar el hecho de que el objeto reside en un espacio de direcciones
distinto, al apoderado virtual realizar optimizaciones como la creación de objetos por
demanda y al apoderado de protección y a las referencias “inteligentes” realizar tareas
adicionales de vigilancia sobre el objeto al que se accede. No obstante todo esto puede
resultar un inconveniente, por motivos de claridad e inteligibilidad del diseño.
· Facilita otra optimización, relacionada con la creación de objetos por demanda : la
técnica de COPY-ON-WRITE, que sólo hace efectiva la copia de un objeto oneroso
cuando el acceso a él es de escritura, no de lectura.
Relacionado con
· Adaptador proporciona al objeto que está adaptando una interfaz diferente,
mientras que Apoderado presenta la misma interfaz que su representado. No obstante,
en el caso del apoderado de protección se pueden rechazar peticiones que el
representado sí puede atender, con lo que, de hecho, se está modificando su interfaz.
________________________________________________________________________________
-8-
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
En un editor de documentos que permite gráficas y dibujos complejos dentro de un
documento se nos plantea el problema de que recuperar todos estos costosos elementos
cada vez que se abre el documento es ineficiente e innecesario, por lo que podemos
definir un “representante”, que ocupe su lugar, hasta que sea necesario cargarlos.
GRÁFICO
EDITOR DE
Dibujar()
DOCUMENTOS Guardar()
Cargar()
ObtenerContorno()
________________________________________________________________________________
IMAGEN REPRESENTANTE
-9- if (imagen == 0)
imagen=CargarImagen(fichero);
Dibujar() imagen Dibujar() imagen -> Dibujar();
Guardar() Guardar()
Cargar() Cargar()
Colección de patrones Banda de los Cuatro
________________________________________________________________________________
- 10 -
Colección de patrones Banda de los Cuatro
Tipo
Comportamiento, a nivel de objetos.
Propósito
Proporcionar a más de un objeto la capacidad de atender una petición, para así
evitar el acoplamiento con el que objeto que hace la petición. Se forma con estos objetos
una cadena, en la cual cada objeto o satisface la petición o la pasa al siguiente.
Estructura
RESPONSABLE sucesor
CLIENTE
AtenderPetición()
AtenderPetición() AtenderPetición()
Cuando usarlo
· Cuando una petición puede ser atendida por más de un objeto y el manejador que
la satisfará no se conoce “a priori”.
· Cuando se quiere trasladar una petición a un objeto de entre unos cuantos, sin
especificar explícitamente el receptor final.
· Cuando el conjunto de objetos que pueden atender una petición se puede
especificar o modificar dinámicamente.
Ventajas
· Se reduce el acoplamiento, puesto que se libera al objeto que hace la petición de
conocer quien se la atiende. No sólo eso, sino que, además, los miembros de la cadena
no conocen la estructura entera, sino sólo su sucesor en la misma.
· Mayor flexibilidad, puesto que se puede añadir o modificar la capacidad de
atender una petición, simplemente haciendo cambios en la cadena de responsabilidades,
dinámicamente (en tiempo de ejecución).
Inconvenientes
· No se garantiza la recepción y satisfacción de una petición, pues puede haber
errores en la configuración de la cadena o también puede ocurrir que ningún elemento de
la cadena sepa atender la petición.
Relacionado con
· Cadena de responsabilidades se usa frecuentemente junto a Composición, donde
lo normal es que el sucesor de un componente en la cadena sea su ancestro en la
estructura jerárquica recursiva.
________________________________________________________________________________
- 11 -
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
En un sistema de ayuda dependiente del contexto para una interfaz gráfica de
usuario (GUI) se pretende que el usuario, pulsando el ratón sobre un elemento gráfico
cualquiera, pueda obtener información de ayuda referente al mismo, siendo ésta distinta
según sea la situación de ese elemento dentro de la interfaz (no es lo mismo un botón en
una caja de diálogo que en la ventana principal de una aplicación). Así, cada elemento
gráfico (un botón, por ejemplo), si puede, debe proporcionar esa información de ayuda y si
no, debe pasar la petición al elemento que define el contexto en el que se encuentra (la
caja de diálogo, por ejemplo), con lo que no se sabe “a priori” quién atenderá, finalmente,
la petición, proporcionando la necesaria información de ayuda.
GESTOR DE AYUDA
________________________________________________________________________________
- 12 -
Colección de patrones Banda de los Cuatro
contexto
AtenderPeticiónDeAyuda()
contexto -> AtenderPeticiónDeAyuda()
DIÁLOGO BOTÓN
MostrarAyuda() si puede dar la ayuda
AtenderPeticiónDeAyuda() MostrarAyuda();
si no
contexto::AtenderPeticiónDeAyuda();
________________________________________________________________________________
- 13 -
Colección de patrones Banda de los Cuatro
COMPOSICIÓN / COMPOSITE
Tipo
Estructura, a nivel de objetos.
Propósito
Permitir a los clientes tratar uniformemente a los objetos simples y compuestos de
una estructura jerárquica recursiva.
Estructura
COMPONENTE
CLIENTE Operación()
hijos
SIMPLE COMPUESTO
Operación() Operación()
para todos los hijos
hijo.Operación();
Cuando usarlo
· Cuando se pretende representar una jerarquía recursiva de objetos.
· Cuando se pretende que los clientes no reparen en las diferencias entre objetos
simples y compuestos.
Ventajas
· Simplifica notablemente al cliente, al no tener éste que distinguir entre objetos
simples y compuestos.
· Favorece la extensibilidad, ya que es muy fácil añadir nuevos tipos de
componentes, tanto simples como compuestos.
Inconvenientes
· Puede hacer el diseño peligrosamente genérico, dificultando la imposición de
restricciones sobre ciertos componentes de la jerarquía (por ejemplo, las comprobaciones
de tipo no se pueden hacer con garantía más que en tiempo de ejecución). Esta es la
otra cara de la facilidad para la extensibilidad.
Relacionado con
· Es frecuente que la relación entre un componente y su padre se use para una
Cadena de Responsabilidades.
· Decorador es muy frecuentemente usado junto a Composición, como un hijo más
del padre común de la jerarquía (“Componente”), por lo que debe adaptarse a su interfaz.
________________________________________________________________________________
- 14 -
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
Un editor de dibujos permite al usuario construir complejas composiciones a partir
de elementos básicos, que se ensamblan unos en/con otros. Utilizando el patrón
Composición podemos usar adecuadamente la composición recursiva para ocultar al
cliente las diferencias entre elementos gráficos sencillos y compuestos.
ELEMENTO GRÁFICO
Dibujar()
ObtenerHijo(int)
Quitar(Componente)
Añadir(Componente c)
componentes
RECTÁNGULO LÍNEA TEXTO DIBUJO
________________________________________________________________________________
- 15 -
Colección de patrones Banda de los Cuatro
Tipo
Creación, a nivel de objetos.
Propósito
Separar la construcción y la representación de un objeto complejo, para así permitir
que el mismo proceso de construcción sirva para crear diferentes representaciones.
Estructura
constructor
DIRECTOR CONSTRUCTOR
Construir() ConstruirParte()
ConstruirParte()
ObtenerResultado()
PRODUCTO
Cuando usarlo
· Cuando el algoritmo de creación del objeto complejo debe ser independiente de
qué partes y cómo lo componen.
· Cuando el proceso de construcción debe soportar diferentes representaciones
para el objeto que se construye.
Ventajas
· El diseño gana en flexibilidad, dado que cambiar la representación interna del
producto que se construye es tan sencillo como definir un nuevo tipo de constructor.
· La separación (independencia) entre el proceso de construcción y la
representación del producto fomenta la reutilización, puesto que permite que diferentes
directores construyan variantes de un producto a partir del mismo conjunto de partes.
· Se favorece el encapsulamiento y el control, puesto que cada constructor concreto
contiene todo el código necesario para crear y ensamblar todas las partes de un producto
y además el constructor crea el producto paso a paso (parte a parte) bajo la supervisión
del director, que al final recibe el producto completo, de manos del constructor.
Relacionado con
· Como constructor de objetos complejos, este patrón es similar a Fábrica
Abstracta. La diferencia reside en que Constructor se centra en la creación de los objetos
paso a paso (parte a parte), mientras Fábrica Abstracta está orientado a familias de
________________________________________________________________________________
- 16 -
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
Un proceso que lea documentos en el formato de intercambio RTF (Rich Text
Format) debe ser capaz de convertirlo a otros muchos formatos de texto. El problema es
que el nº de los mismos es abierto y desconocido, por lo que debe ser fácil añadir uno
nuevo sin tocar al proceso que lee los documentos en RTF.
________________________________________________________________________________
- 17 -
Colección de patrones Banda de los Cuatro
LECTOR RTF
constructor constructores
CONVERSOR DE TEXTO
TraducirRTF() ConvertirCarácter(char)
ConvertirCambioDeFuente(fuente)
ConvertirParrafo()
________________________________________________________________________________
- 18 -
Colección de patrones Banda de los Cuatro
DECORADOR / DECORATOR
Tipo
Estructura, a nivel de objetos.
Propósito
Añadir responsabilidades adicionales a un objeto dinámicamente, proporcionando
una alternativa flexible a la especialización mediante herencia, cuando se trata de añadir
funcionalidades.
Estructura
COMPONENTE
Operación()
Decorador::Operación();
Comportamiento();
Comportamiento() Operación()
Operación()
EstadoAnidado
Cuando usarlo
· Cuando se quiere añadir responsabilidades a un objeto de manera dinámica y
transparente (independientemente de otros objetos).
· Cuando es imposible la extensión de funcionalidad por herencia, por ser aquella
imprevisible en tipo y número.
Ventajas
· Aporta una mayor flexibilidad que la herencia estática, permitiendo, entre otras
cosas, añadir una funcionalidad dos o más veces.
· Evita concentrar en lo alto de la jerarquía clases “guiadas por las
responsabilidades”, es decir, que pretenden (en vano) satisfacer todas las posibilidades.
De esta forma las nuevas funcionalidades se componen de piezas simples que se crean y
se combinan con facilidad, independientemente de los objetos cuyo comportamiento
extienden.
Inconvenientes
· La transparencia tiene el inconveniente de que, a pesar de ser diferentes por
muchos motivos, un decorador y un componente son indistinguibles, por lo que no se
puede confiar en la identidad de los objetos.
________________________________________________________________________________
- 19 -
Colección de patrones Banda de los Cuatro
Relacionado con
· Adaptador cambia la interfaz de un objeto (ocasionalmente puede tener que
añadir alguna funcionalidad) mientras que Decorador centra su atención en ampliar las
responsabilidades de un objeto, sin tocar su interfaz.
· Decorador puede ser visto como una degeneración de Composición con un sólo
componente, que además extiende funcionalidades.
· Decorador permite cambiar la “piel” de un objeto, mientras que Estrategia cambia
sus “entrañas”. Esto hace que frente a la TRANSPARENCIA que da Decorador respecto
a los componentes, Estrategia presenta una interfaz propia e independiente, que no tiene
porque amoldarse a la de los componentes6.
Ejemplo de aplicación
En los conjuntos de utilidades para interfaces gráficas de usuario (GUI) se puede
permitir añadir a los componentes visuales propiedades (por ejemplo, un borde) o
comportamientos (por ejemplo, una barra de desplazamiento).
COMPONENTE VISUAL
Dibujar()
Decorador::Dibujar();
DibujarBorde();
DibujarBorde() Dibujar()
Dibujar() DesplazarHasta()
AnchoDelBorde PosiciónDeDesplazamiento
5
Esta es la esencia del paradigma orientado a objetos, luego no veo porque ha de ser un inconveniente.
6
Los autores de este catálogo parecen replantearse la “bondad” de Decorador y se inclinan por Estrategia.
________________________________________________________________________________
- 20 -
Colección de patrones Banda de los Cuatro
ESTADO / STATE
Tipo
Comportamiento, a nivel de objetos.
Propósito
Permitir a un objeto modificar su comportamiento a medida que su estado interno
va cambiando, dando así la impresión de que el objeto “cambia de clase”.
Estructura
estado
CONTEXTO ESTADO
Petición() Atender()
Cuando usarlo
· Cuando el comportamiento de un objeto depende de su estado y debe poder
cambiar dinámicamente (en tiempo de ejecución) dicho comportamiento, a medida que
cambie dicho estado.
· Cuando las operaciones tienen definiciones largas y con múltiples condiciones,
dependientes del estado del objeto, siendo lo más adecuado separar en objetos
independientes cada condición “atómica”, para poder así combinarlas y modificarlas
independientemente, ya sea en estados ya existentes, ya en otros nuevos que se formen
combinándolos.
Ventajas
· Dado que el comportamiento específico de cada estado está autocontenido en
cada estado concreto, existe una gran flexibilidad para añadir nuevos estados y
transiciones, mediante la definición de nuevas subclases.
· A pesar de que la distribución del comportamiento ante diferentes situaciones
entre diferentes objetos incrementa el nº de clases y reduce la compacidad, es la mejor
solución cuando hay muchos estados, pues evita las definiciones multicondicionales y
grandes, tan indeseables como los procedimientos gigantes lo son en el estilo imperativo.
· Se hacen más explícitas las transiciones entre estados que sí todo estuviera
concentrado en una sola clase (esto hace más inteligible el diseño), impidiendo además
los estados internos inconsistentes (desde el punto de vista del contexto, los cambios de
estado son ATÓMICOS).
· Si los objetos que representan los estados no tienen variables de instancia (esto
es, el estado está totalmente definido en su propio tipo) entonces diferentes contextos
pueden compartir estados, como PesoMosca sin estado intrínseco, sólo comportamiento.
Relacionado con
________________________________________________________________________________
- 21 -
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
Para cualquier protocolo de comunicaciones el comportamiento que manifiesta
depende directamente del estado en que se encuentre : conectado, escuchando, cerrado,
etc...
Abrir()
Abrir() Cerrar()
Cerrar() MandarConfirmación()
MandarConfirmación()
ESTRATEGIA / STRATEGY
7
¡Estado centra su atención en el comportamiento dependiente del estado y la aproximación basada en tablas
en las transiciones entre estados!
________________________________________________________________________________
- 22 -
Colección de patrones Banda de los Cuatro
Tipo
Comportamiento, a nivel de objetos.
Propósito
Definir una familia de algoritmos encapsulando por separado cada uno de ellos y
haciéndolos, por tanto, intercambiables. Esto permite a los algoritmos variar con
independencia de los clientes que los usan.
Estructura
estrategia
CONTEXTO ESTRATEGIA
InterfazDelContexto() InterfazDelAlgoritmo()
Cuando usarlo
· Cuando muchas clases relacionadas sólo se diferencian en su comportamiento.
· Cuando se necesitan diferentes variantes de un algoritmo.
· Cuando un algoritmo usa datos que los clientes no tienen porque conocer.
· Cuando una clase define muchos comportamientos, los cuales se manifiestan
como definiciones condicionales múltiples de sus operaciones.
Ventajas
· Las familias jerárquicas de estrategias definen algoritmos y comportamientos que
enfatizan la reutilización. La herencia puede ayudar a sacar factor común a la
funcionalidad de los algoritmos.
· El encapsulamiento de algoritmos en clases separadas ofrece una ventajosa
alternativa a la especialización por herencia del contexto para obtener un comportamiento
diferente, que promueve la independencia, la facilidad de entender el diseño y la
posibilidad de futuras extensiones.
· Se eliminan las costosas definiciones de comportamiento multicondicionales.
· Se posibilita ofrecer diferentes implementaciones del mismo comportamiento, en
función de restricciones como el espacio en memoria o el tiempo de respuesta.
Inconvenientes
· Los clientes deben tener un cierto conocimiento de cada estrategia, para así
poder elegir en cada situación cual es la más apropiada.
· Dado que todas las estrategias comportan una interfaz común, si las diferencias
entre ellas es grande, es probable que mucha de la información que se les pasa no sea
de utilidad más que a las más complejas.
· Puede producirse una gran explosión en el número de objetos del sistema. Esto
se puede aliviar si las estrategias se implementan como objetos sin estado que los
contextos pueden compartir (ver PesoMosca).
________________________________________________________________________________
- 23 -
Colección de patrones Banda de los Cuatro
Relacionado con
· Los objetos Estrategia a menudo son buenos PesosMosca.
Ejemplo de aplicación
En un editor de texto pueden existir múltiples algoritmos para dividir un documento
en lineas (algoritmo simple, algoritmo TEX, algoritmo matricial, etc ...), siendo deseable
que la complejidad de los mismos quede oculta al cliente y que sea fácil y cómodo el
cambio sobre la marcha de uno por otro o la adición de nuevos algoritmos al sistema.
algoritmo
DOCUMENTO
Recorrer()
Repaginar()
ALGORITMO
···············
algoritmo -> DividirEnLineas(); DividirEnLineas()
···············
________________________________________________________________________________
- 24 -
Colección de patrones Banda de los Cuatro
Tipo
Creación, a nivel de objetos.
Propósito
Proporcionar una interfaz para la creación de familias de objetos interdependientes
o interrelacionados, sin especificar sus clases concretas.
Estructura
PRODUCTO PRODUCTO
ABSTRACTO A CLIENTE ABSTRACTO B
FABRICA ABSTRACTA
CrearProductoA()
CrearProductoB()
CrearProductoA() CrearProductoA()
CrearProductoB() CrearProductoB()
Cuando usarlo
· Cuando el sistema debe ser independiente de como sus productos se crean,
componen y representan.
· Cuando el sistema debe configurarse con una familia de productos de entre
múltiples posibles.
· Cuando se quiere dar énfasis a la restricción de que una familia de productos ha
sido diseñada para que actúen todos juntos.
· Cuando se quiere proporcionar una librería de clases de productos, de los que
sólo se desea revelar su interfaz, no su implementación.
Ventajas
________________________________________________________________________________
- 25 -
Colección de patrones Banda de los Cuatro
Inconvenientes
· Se dificulta la extensibilidad, puesto que no es fácil añadir nuevos tipos de
productos8.
Relacionado con
· La implementación de las clases contenidas en este patrón lleva, usualmente, a
otros dos patrones : Método de Fábrica y Prototipo.
· Como lo más usual es que sólo necesitemos una fábrica concreta por familia de
productos, esto nos allega al patrón Solitario.
Ejemplo de aplicación
En el diseño de una interfaz de usuario que dé soporte a múltiples estándares de
presentación, como Motif o Presentation Manager, los diferentes estándares de
presentación definen diferentes aspectos y comportamientos en elementos gráficos de la
interfaz de usuario, tales como : barras de desplazamiento, ventanas o botones.
CrearBarraDeDesplazamiento()
CrearVentana()
CrearBarraDeDesplazamiento() CrearBarraDeDesplazamiento()
CrearVentana() CrearVentana()
FACHADA / FACADE
8
Existe un conflicto, ya clásico, entre la extensibilidad y la flexibilidad.
________________________________________________________________________________
- 26 -
Colección de patrones Banda de los Cuatro
Tipo
Estructura, a nivel de objetos.
Propósito
Proporcionar una interfaz unificada de alto nivel que, representando a todo un
subsistema, facilite su uso. La “fachada” satisface a la mayoría de los clientes, sin ocultar
las funciones de menor nivel a aquellos que necesiten acceder a ellas.
Estructura
FACHADA
Cuando usarlo
· Cuando se pretende proporcionar una interfaz simple para un subsistema
complejo.
· Cuando existen muchas dependencias entre los clientes y las clases que
implementan una abstracción. Una “fachada” proporciona al subsistema independencia y
portabilidad.
· Cuando se pretende estructurar en capas el subsistema (cada capa tendrá su
propia “fachada”).
Ventajas
· Al separar al cliente de los componentes del subsistema, se reduce el número de
objetos con los que el cliente trata, facilitando así el uso del subsistema.
· Se promueve un acoplamiento débil entre el subsistema y sus clientes,
eliminándose o reduciéndose las dependencias.
· No existen obstáculos para que las aplicaciones usen las clases del subsistema
que necesiten. De esta forma podemos elegir entre facilidad de uso y generalidad.
Relacionado con
________________________________________________________________________________
- 27 -
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
En un entorno de programación se permite a las aplicaciones el acceso al
subsistema de compilación. Este subsistema contiene clases como el AnalizadorLéxico,
el AnalizadorSintáctico, el AnalizadorSemántico, el GeneradorDeCódigoIntermedio o el
GeneradorDeCódigoFinal. No obstante sólo aplicaciones muy especiales necesitan
acceder directamente a algunas de estas clases, mientras que para el resto se puede
definir una interfaz general, una “fachada”, que les permita sencillamente compilar sus
programas.
COMPILADOR
CLASES DEL SUBSISTEMA DE Compilar()
COMPILACIÓN
Cadena
AnalizadorLéxico Token
AnalizadorSintáctico Símbolo
CadenaEnCódigoBit
ConstructorDeNodosDePrograma NodoDePrograma
GeneradorDeCódigo
NodoDeDefinición
NodoDeVariable
GeneradorDeCódigo para GeneradorDeCódigo para
una Máquina de Pila una Máquina RISC NodoDeExpresión
INTÉRPRETE / INTERPRETER
________________________________________________________________________________
- 28 -
Colección de patrones Banda de los Cuatro
Tipo
Comportamiento, a nivel de clases.
Propósito
Dado un lenguaje, define una representación para su gramática junto con un
intérprete que usa dicha representación para interpretar sentencias en ese lenguaje.
Estructura
Interpretar(contexto)
Interpretar(contexto) Interpretar(contexto)
Cuando usarlo
· Principalmente, cuando haya un lenguaje que interpretar y sus diferentes
construcciones puedan representarse mediante árboles sintácticos abstractos. Da sus
mejores resultados cuando la gramática es simple (con gramáticas complejas la jerarquía
de clases se hace inmanejable y es mejor usar generadores automáticos de analizadores
sintácticos) y la eficiencia no es una cuestión vital (existen formas más eficientes de
interpretar, usando máquinas de estado finitas en lugar de árboles sintácticos).
Ventajas
· Facilidad para cambiar o extender la gramática, mediante herencia, dado que las
diferentes reglas de la gramática se representan con clases.
· Facilidad para implementar la gramática, dado que las implementaciones de las
clases nodo del árbol sintáctico son similares, pudiendo usarse para ello generadores
automáticos de código.
· Facilidad para introducir nuevas formas de “interpretar” las expresiones en la
gramática (tener en cuenta el patrón Visitante).
Inconvenientes
· Limitación en el tipo de gramáticas (y, por extensión, de problemas) para los que
sirve esta aproximación : simples y sin grandes necesidades de eficiencia. Aunque el uso
de otros patrones puede mitigar este problema, hay circunstancias en que un Intérprete
no es lo más apropiado.
Relacionado con
· Considerado en su forma más general (una operación distribuida sobre una
jerarquía de clases basada en el patrón Composición), prácticamente toda aparición de
éste lleva unida la de un Intérprete. Pero es una cuestión de perspectiva (¡subjetiva!) la
que nos lleva a plantearnos un Intérprete sólo cuando la jerarquía de clases (árbol
sintáctico) define un lenguaje.
________________________________________________________________________________
- 29 -
Colección de patrones Banda de los Cuatro
· PesoMosca ofrece una forma de “compartir” los símbolos terminales del árbol
sintáctico.
· El Intérprete puede usar un Iterador para recorrer la estructura.
· Visitante puede servir para mantener el comportamiento de cada nodo del árbol
sintáctico abstracto en una sola clase.
Ejemplo de aplicación
El problema de encontrar palabras que encajen en un patrón se puede resolver
definiendo un lenguaje para ello, por ejemplo mediante “Expresiones Regulares”. Esto
nos permite ya aplicar un “Intérprete” a dicho lenguaje para resolver el problema :
________________________________________________________________________________
EXPRESIÓN REGULAR
repetición - 30 - expresión2
Interpretar()
expresión1
Colección de patrones Banda de los Cuatro
________________________________________________________________________________
- 31 -
Colección de patrones Banda de los Cuatro
ITERADOR / ITERATOR
Tipo
Comportamiento, a nivel de objetos.
Propósito
Proporcionar una forma de acceder secuencialmente a los elementos de un objeto
compuesto por agregación sin necesidad de desvelar su representación interna.
Estructura
AGREGADO ITERADOR
CLIENTE
CrearIterador() Primero()
Siguiente()
Actual()
Primero()
CrearIterador() return new IteradorConcreto(this); Siguiente()
Actual()
Cuando usarlo
· Cuando se quiere acceder a los elementos de un objeto agregado sin mostrar su
representación interna.
· Cuando se quieren permitir recorridos múltiples en objetos agregados.
· Cuando se quiere proporcionar una interfaz uniforme para recorrer diferentes
estructuras de agregación (iteración polimórfica9).
Ventajas
· Se incrementa la flexibilidad, dado que para permitir nuevas formas de recorrer
una estructura basta con modificar el iterador en uso, cambiarlo por otro
(¡parametrización!) o definir uno nuevo.
· Se enfatiza la distribución de responsabilidades (y, por ello, la simplicidad de los
elementos del sistema), dado que la interfaz del agregado se ve libre de una serie de
operaciones, más propias de la interfaz del iterador.
· Se facilitan el paralelismo y la concurrencia, puesto que, como cada iterador tiene
consciencia de su estado en cada momento, es posible que dos o más iteradores recorran
una misma estructura simultánea o solapadamente.
Relacionado con
· Iterador se aplica a menudo a estructuras recursivas del tipo de Composición.
· Los Iteradores polimórficos se basan en Método de Fábrica a la hora de instanciar
el tipo de iterador apropiado a cada caso.
9
Usar sólo en caso de necesidad.
________________________________________________________________________________
- 32 -
Colección de patrones Banda de los Cuatro
· También es habitual que Iterador use un Recuerdo para capturar el estado de una
iteración, de forma interna.
Ejemplo de aplicación
Una lista es un objeto agregado que puede beneficiarse de un “Iterador” que lo
recorra sin exponer su estructura interna, permitiendo así diferentes tipos de listas (listas
normales, listas de tipo “skip”10, ...) y diferentes tipos de iteradores.
10
Una lista “skip” es una estructura de datos probabilística de características similares a los árboles
balanceados.
________________________________________________________________________________
- 33 -
Colección de patrones Banda de los Cuatro
MEDIADOR / MEDIATOR
Tipo
Comportamiento, a nivel de objetos.
Propósito
El diseño OO enfatiza la distribución de responsabilidades entre objetos. Tal
distribución puede devenir en una estructura con muchas conexiones entre objetos (en el
peor caso, todos con todos). Aunque la distribución favorece la REUTILIZACIÓN, la
proliferación de relaciones entre objetos puede ser un grave obstáculo. Por ello, este
patrón define un objeto que encapsula la forma en que interactúan un grupo de objetos,
promoviendo así un acoplamiento débil al evitar las referencias explícitas entre los objetos
y permitiendo, por tanto, que su interacción se modifique de forma independiente.
Estructura
mediador
MEDIADOR COLABORADOR
Cuando usarlo
· Cuando existe un conjunto de objetos cuya comunicación está bien definida pero
es compleja, con lo que las interdependencias que surgen están poco estructuradas y son
difíciles de entender.
· Cuando reutilizar un objeto se ve dificultado por la cantidad de referencias que
tiene a otros objetos.
· Cuando un comportamiento distribuido entre varias clases debe ser adaptable a
las circunstancias, sin tener que abusar de la especialización por herencia.
Ventajas
· Se limita el uso de la herencia, al concentrar en el “Mediador” un comportamiento
que, de otro modo, estaría distribuido entre diversos objetos. Modificar este
comportamiento puede requerir especializar el “Mediador”, pero ya no afectará a los
objetos que interactúan.
· Al reducir el acoplamiento entre los objetos que interactúan es más fácil variar o
reutilizar dichos objetos y el “Mediador”, independientemente.
· Se simplifican los protocolos de comunicación entre los objetos, al sustituir las
relaciones “muchos-a-muchos” por relaciones “uno-a-muchos”, que son más sencillas de
entender, mantener y extender.
· Al hacer de la mediación un concepto independiente, encapsulado en un objeto
aparte, se favorece el centrar la atención en la interacción entre objetos, al margen del
comportamiento individual de cada uno.
Inconvenientes
________________________________________________________________________________
- 34 -
Colección de patrones Banda de los Cuatro
Relacionado con
· La diferencia entre Mediador y Fachada es que el protocolo del primero es
multidireccional, mientras que el del segundo es sólo unidireccional (de la “Fachada” hacia
los elementos del subsistema).
· Los “Colaboradores” pueden comunicarse con el Mediador usando el patrón
Observador.
Ejemplo de aplicación
En una Interfaz Gráfica de Usuario (GUI) hay, entre otras cosas, elementos como
los cuadros de diálogo, que contienen, dentro de una ventana, una serie de elementos
gráficos (botones, menús, campos de entrada de datos, etc ...) para permitir al usuario
una interacción rápida y fácil con el sistema. Las interrelaciones entre dichos elementos
gráficos contenidos en un cuadro de diálogo son a la vez tan complejas y variables (son
diferentes en cada cuadro y aún dentro del mismo, según las circunstancias) que la
utilización de un Mediador para controlar y coordinar dichas relaciones es muy útil.
director
DIRECTOR DE DIÁLOGO ELEMENTO GRÁFICO
MostrarDiálogo() Cambiado()
CrearElementosGráficos() director->ElementoCambiado(this);
ElementoCambiado(elem)
DIRECTOR DE DIÁLOGO
botón BOTÓN CAMPO DE ENTRADA
BASICO
DE DATOS
Activar()
CrearElementosGráficos() Desactivar() IntroducirTexto()
ElementoCambiado(elem)
campo
Tipo
Creación, a nivel de clases.
11
Todos los inconvenientes de cualquier sistema centralizado son válidos también en este caso.
________________________________________________________________________________
- 35 -
Colección de patrones Banda de los Cuatro
Propósito
Definir una interfaz para la creación de un objeto, pero permitiendo a las subclases
decidir de que clase instanciarlo. Permite, por tanto, que una clase difiera la instanciación
en favor de sus subclases.
Estructura
CREADOR
MétodoFábrica()
UnaOperación() ···
PRODUCTO producto = MétodoFábrica();
···
MétodoFábrica()
return new ProductoConcreto();
Cuando usarlo
· Cuando una clase no puede adelantar las clases de objetos que debe crear.
· Cuando una clase pretende que sus subclases especifiquen los objetos que ella
crea.
· Cuando una clase delega su responsabilidad hacia una de entre varias subclases
auxiliares y queremos tener localizada a la subclase delegada.
Ventajas
· Se gana en flexibilidad, pues crear los objetos dentro de una clase con un
“Método de Fábrica” es siempre más flexible que hacerlo directamente, debido a que se
elimina la necesidad de atar nuestra aplicación unas clases de productos concretos.
· Se facilitan futuras ampliaciones, puesto que se ofrece las subclases la posibilidad
de proporcionar una versión extendida de un objeto, con sólo aplicar en los Productos la
misma idea del “Método de Fábrica”.
· Se facilita, en cuanto a que se hace natural, la conexión entre jerarquías de clases
paralelas, que son aquellas que se generan cuando una clase delega algunas de sus
responsabilidades en una clase aparte. Ambas jerarquías de clases paralelas son
creadas por un mismo cliente y el patrón Método de Fábrica establece la relación entre
parejas de subclases concretas en las mismas.
Inconvenientes
· Se obliga al cliente a definir subclases de la clase “Creador” sólo para crear un
producto concreto y esto puede no ser apropiado siempre12.
12
Se resuelve parametrizando o usando las plantillas de C++ (templates).
________________________________________________________________________________
- 36 -
Colección de patrones Banda de los Cuatro
Relacionado con
· Fábrica Abstracta es frecuentemente implementado con Método de Fábrica.
· Método de Fábrica habitualmente se utiliza dentro de Método Plantilla.
· Prototipo no requiere hacer subclases de “Creador”, pero sí una operación de
“Inicializar” en la clase “Producto”, que no le hace falta a Método de Fábrica.
Ejemplo de aplicación
En un “marco de referencia” para aplicaciones que pueden presentar múltiples
documentos al usuario, no se sabe, a priori, los tipos de documentos con los que va a
trabajar cada aplicación concreta. El “marco de referencia” debe, por tanto, instanciar
clases, pero sólo tiene conocimiento de las clases abstractas, las cuales no pueden ser
instanciadas. La solución está en hacer que CrearDocumento() sea un Método de Fábrica que
se encargue de la “fabricación” del objeto oportuno en cada situación (es una operación
abstracta en la clase abstracta , pero concreta y distinta en las subclases
correspondientes a cada tipo de aplicación.
docs
DOCUMENTO APLICACIÓN
Abrir() CrearDocumento()
Cerrar() AbrirDocumento()
Guardar() NuevoDocumento() Documento *doc = CrearDocumento();
VoverAtrás() docs.Añadir(doc);
doc -> Abrir();
CrearDocumento()
return new DocumentoGráfico;
Propósito
________________________________________________________________________________
- 37 -
Colección de patrones Banda de los Cuatro
Estructura
CLASE ABSTRACTA
···
OperaciónPrimitiva1() OperaciónPrimitiva1();
OperaciónPrimitiva2() ···
MétodoPlantilla() OperaciónPrimitiva2();
···
CLASE CONCRETA
OperaciónPrimitiva1()
OperaciónPrimitiva2()
Cuando usarlo
· Cuando se pretende implementar una sola vez las partes invariantes de un
algoritmo, permitiendo a las subclases implementar el comportamiento que puede variar.
· Cuando se quiere “sacar factor común” del comportamiento compartido por varias
clases para localizarlo en un única clase, que evita la duplicación de código. A esta
técnica se la conoce comúnmente como REFACTORIZAR PARA GENERALIZAR y sigue
el esquema :
+ Identificar las diferencias en el código ya existente.
+ Separarlas, convirtiéndolas en operaciones nuevas.
+ Reemplazar las diferencias en el código existente por un “MétodoPlantilla”
que invoque a las operaciones que necesite.
· Cuando se quieren controlar las extensiones de las subclases, definiendo
“MétodosPlantilla” que invocan operaciones adaptables (la clase abstracta da una
implementación por defecto, que suele ser vacía, pero las subclases pueden redefinirla),
que son las que permiten extender el comportamiento.
Ventajas
· Los “MetodosPlantilla” son una técnica fundamental para reutilizar código,
especialmente en las librerías de clases, donde son la razón de ser de la “factorización de
comportamiento común”. Llevan a una estructura de control invertido, cuyo paradigma es
el “Principio de Hollywood” : <<NO NOS LLAME, YA LE LLAMAREMOS>>, esto es, la
clase padre invoca la implementación que la clase hija hace de operaciones primitivas,
pero no al revés.
Relacionado con
· Los Métodos de Fábrica están entre las operaciones a las que más
frecuentemente invoca un Método Plantilla, junto con operaciones concretas (tanto de la
clase abstracta como de la clase concreta), las operaciones primitivas abstractas y las
operaciones adaptables.
________________________________________________________________________________
- 38 -
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
En un “marco de referencia” para aplicaciones y documentos, las aplicaciones son
las responsables de abrir los documentos almacenados en un formato externo al sistema
(un fichero, por ejemplo), mientras que los documentos representan y dan formato a la
información, una vez ésta es leída del fichero. Dado que este “marco de referencia”
puede usarse para muchos tipos de aplicaciones y documentos, se pueden definir
Métodos Plantilla (por ejemplo, NuevoDocumento()) que definan los algoritmos que satisfacen
las operaciones genéricas, mientras las subclases aportan el conocimiento preciso para
dotarlos de un comportamiento concreto.
docs
DOCUMENTO APLICACIÓN
Abrir() Hacer-CrearDocumento()
Cerrar() AbrirDocumento()
Guardar() NuevoDocumento() Documento *doc = Hacer-CrearDocumento();
Hacer-Leer() docs.Añadir(doc);
doc -> Abrir();
________________________________________________________________________________
DOCUMENTO GRÁFICO APLICACIÓN GRÁFICA
- 39 -
Hacer-CrearDocumento()
return new DocumentoGráfico;
Colección de patrones Banda de los Cuatro
Hacer-Leer()
________________________________________________________________________________
- 40 -
Colección de patrones Banda de los Cuatro
OBSERVADOR / OBSERVER
Tipo
Comportamiento, a nivel de objetos.
Propósito
Un efecto lateral muy frecuente en aquellos sistemas que se fragmentan en un
conjunto de clases que cooperan es la necesidad de mantener la consistencia entre los
distintos objetos interrelacionados. Para no recurrir a soluciones fuertemente acopladas
(que reducen la posibilidad de reutilización), este patrón define una dependencia “uno-a-
muchos” entre objetos, para que, cuando uno de ellos cambie su estado, todos los que
dependan de él sean avisados y puedan actualizarse convenientemente.
Estructura
ASUNTO observadores OBSERVADOR
Ligar(Observador) Actualizar()
Desligar(Observador)
Notificar() para todo observador
{Actualizar()}
asunto OBSERVADOR
CONCRETO
ASUNTO CONCRETO EstadoDelObservador = Actualizar()
asunto -> ObtenerEstado();
FijarEstado()
ObtenerEstado() EstadoDelObservador
return EstadoDelAsunto;
EstadoDelAsunto
Cuando usarlo
· Cuando una abstracción presenta dos aspectos, un dependiente del otro.
Encapsular estos aspectos en objetos separados nos permite variar y reutilizarlos
independientemente.
· Cuando un cambio en un objeto requiere cambiar otros objetos y no sabemos
cuántos exactamente lo necesitarán.
· Cuando un objeto debe poder notificar sus cambios a otros objetos, sin necesidad
de saber nada acerca de su identidad (acoplamiento débil).
Ventajas
· Dado que el “Asunto” no conoce la clase de “Observadores” que tiene, el
acoplamiento que existe es mínimo y abstracto. Por ello, tanto unos como otros pueden
variar y evolucionar en diferentes niveles de detalle de forma independiente.
· Se facilita y simplifica el “radiado” de las notificaciones. El “Asunto” sólo tiene que
comunicar los cambios; luego, cada “Observador” es libre para hacer o no caso. Esto
permite gran libertad a la hora de dar de alta o baja a los “Observadores”.
Inconvenientes
· Dado el desconocimiento que unos “Observadores” tienen de los otros, cualquier
operación aparentemente inofensiva puede originar una cascada de costosas
actualizaciones. Además, sin un protocolo preciso, en el que se especifique lo que
cambia, el esfuerzo se multiplica.
________________________________________________________________________________
- 41 -
Colección de patrones Banda de los Cuatro
Relacionado con
· Un Gestor de Cambios que encapsula la semántica de actualizaciones en las
relaciones complejas entre “Asuntos” y “Observadores” actúa como Mediador.
· Un Gestor de Cambios puede usar el patrón Solitario para hacerse único y
globalmente accesible.
Ejemplo de aplicación
Un “RelojDigital” y un “RelojAnalógico” observan como cambia el estado de un
“Temporizador” y se actualizan de acuerdo con dichos cambios de estado.
Notificar() Actualizar()
asunto
TEMPORIZADOR RELOJ ANALÓGICO RELOJ DIGITAL
PulsoDeReloj() Actualizar() Actualizar()
asunto
PESO MOSCA / FLYWEIGHT
________________________________________________________________________________
- 42 -
Colección de patrones Banda de los Cuatro
Tipo
Estructura, a nivel de objetos.
Propósito
Mejorar la eficiencia a la hora de mantener una gran cantidad de objetos “de grano
fino”, usando la idea de la compartición. Un “PesoMosca” es un objeto compartido que
puede ser usado en diferentes contextos simultáneamente, de forma transparente,
indistinguible. El concepto clave aquí es la distinción entre el ESTADO INTRÍNSECO
(información independiente del contexto del objeto, almacenada en el mismo y que
favorece su compartición) y el ESTADO EXTRÍNSECO (información que depende y varía
con el contexto donde se use el objeto, no puede ser compartida y se la proporciona el
cliente que lo usa, a través de la fábrica) del objeto compartido.
Estructura
ObtenerPesoMosca(clave) Operación(EstadoExtrínseco)
CLIENTE
Cuando usarlo
Cuando sea cierto que :
· La aplicación usa un gran número de objetos.
· Los costes de almacenamiento son prohibitivos como consecuencia de lo anterior.
· La mayor parte del estado del objeto puede considerarse extrínseco.
· Muchos grupos de objetos pueden reemplazarse por unos pocos objetos
compartidos una vez que se ha prescindido del estado extrínseco.
· La aplicación no depende de la identidad de los objetos, “difuminada” como
consecuencia de la compartición de los mismos.
Ventajas
· Mejora en la eficiencia, sobre todo en relación con el ahorro en el
almacenamiento, que aumenta paralelamente con la compartición de objetos y es función
de :
(a) la reducción en el nº total de instancias.
(b) la cantidad de estado intrínseco por objeto.
(c) si el estado extrínseco es computado (calculado) o almacenado.
Inconvenientes
· Se introducen costes en tiempo de ejecución asociados a las transferencias,
búsquedas y/o computación del estado extrínseco (y su almacenamiento).
________________________________________________________________________________
- 43 -
Colección de patrones Banda de los Cuatro
Relacionado con
· PesoMosca se combina habitualmente con Composición para implementar
estructuras jerárquicas lógicas en términos de grafos acíclicos dirigidos con nodos hoja
compartidos. Como consecuencia de la compartición un nodo hoja no puede tener un
puntero a su padre (ambigüedad, pues tiene varios), si no que éste se le pasa como parte
del estado extrínseco.
· Suele ser muy ventajoso implementar Estado y Estrategia como PesosMosca.
Ejemplo de aplicación
En un editor de documentos podemos tener una jerarquía recursiva de elementos
gráficos, tales como filas, columnas, caracteres, etc ... algunos de los cuales tendrá
sentido hacer compartibles, por motivos de eficiencia. Tal es el caso de los caracteres. Si
por cada carácter del documento creamos un objeto los problemas de almacenamiento
aparecerán de inmediato, mientras que éstos se resolverán fácilmente si sólo se crea un
objeto por cada tipo distinto de carácter (256, en ASCII), compartible por cada aparición
de los mismos en el texto, en diferentes posiciones (este sería su estado extrínseco).
ELEMENTO GRÁFICO
Dibujar(Contexto)
Intersectar(Punto,Contexto)
hijos hijos
FILA CARÁCTER COLUMNA
char c
PROTOTIPO / PROTOTYPE
Tipo
Creación, a nivel de objetos.
Propósito
________________________________________________________________________________
- 44 -
Colección de patrones Banda de los Cuatro
Especificar los tipos de objetos que queremos crear usando una instancia
prototípica y crear nuevos objetos copiando dicho prototipo.
Estructura
Operación() Clonar()
Cuando usarlo
· Cuando el sistema debe ser independiente de como se crean, componen y
representan sus productos .... (y)
· Cuando las clases a instanciar se especifican en tiempo real o se quiere evitar
construir una jerarquía de fábricas paralela a la de productos o las instancias de una clase
pueden tomar una de entre unas pocas combinaciones distintas de estado.
Ventajas
· Potencia el encapsulamiento, ya que, al igual que Fábrica Abstracta y Constructor,
oculta al cliente las clases de productos concretos con los que trabaja.
· Dota al sistema de una mayor flexibilidad, pues se pueden añadir/eliminar
productos concretos dinámicamente13.
· Se pueden definir nuevos tipos de objetos instanciando clases ya existentes y
registrando estas instancias como nuevos prototipos para el cliente. Por tanto, se pueden
definir “nuevas clases” SIN PROGRAMAR NADA.
· Se reduce drásticamente la especialización mediante herencia, lo cual siempre
ayuda a la reutilización. En C++, esto es especialmente útil puesto que no hay
metaclases, con lo cual las clases no son objetos de primer orden y tampoco hay
información de tipos en tiempo de ejecución.
· Permite configurar una aplicación en tiempo de ejecución (añadir/eliminar clases
dinámicamente).
Inconvenientes
· Cada subclase de “Prototipo” debe implementar la operación “Clonar” y esto
puede resultar difícil en clases que ya existen o que incluyen objetos que no admiten la
copia o que contienen referencias circulares.
Relacionado con
· Prototipo y Fábrica Abstracta son patrones rivales en muchos sentidos, aunque
también pueden trabajar juntos, cooperando.
13
En esto es superior a los otros patrones de creación.
________________________________________________________________________________
- 45 -
Colección de patrones Banda de los Cuatro
· Aquellos diseños que hacen un uso muy acentuado de los patrones Composición
y Decorador frecuentemente pueden beneficiarse también del patrón Prototipo.
Ejemplo de aplicación
Para hacer un editor de música podemos adaptar un “marco de referencia” para
editores gráficos en general, añadiendo las clases de elementos gráficos que necesitemos
como las notas, los silencios o el pentagrama. El problema surge cuando, como
frecuentemente ocurre, dicho “marco de referencia” proporciona una paleta de
herramientas para manipular los elementos gráficos (añadir, seleccionar, mover, etc ...),
puesto que dichas herramientas, al no conocer estas clases específicas de elementos
gráficos, no saben como crearlos. La solución está en hacer que las herramientas creen
cualquier elemento gráfico mediante copia o “clonación” de una instancia de una subclase
de la clase abstracta y general que representa dichos elementos gráficos. Dicha instancia
recibe el nombre de prototipo.
Manipular() Dibujar(posición)
Clonar()
p = prototipo->Clonar();
while (usuario mueva el ratón)
p->Dibujar (nueva_posición);
insertar p en el dibujo; return return return
(copia de si mismo); (copia de si mismo); (copia de si mismo);
PUENTE / BRIDGE
Tipo
Estructura, a nivel de objetos.
Propósito
Separar una abstracción de su implementación para permitir que ambos puedan
variar independientemente.
________________________________________________________________________________
- 46 -
Colección de patrones Banda de los Cuatro
Estructura
imp
ABSTRACCIÓN IMPLEMENTACIÓN
ABSTRACCIÓN
REFINADA IMPLEMENTACIÓN IMPLEMENTACIÓN
CONCRETA 1 CONCRETA 2
Implementación() Implementación()
imp->Implementación();
Cuando usarlo
· Cuando se quiere evitar una unión permanente entre abstracción e
implementación.
· Cuando se quiere extender tanto abstracción como implementación por herencia.
· Cuando se quiere evitar que posibles cambios en la implementación de una
abstracción afecten a los clientes.
· Cuando se quiere ocultar la implementación de la vista de los clientes.
· Cuando se tiene que hacer frente a una proliferación de clases tal que el uso de la
herencia no es recomendable por su inflexibilidad.
· Cuando se quiere tener muchos objetos compartiendo una misma implementación
de manera transparente al cliente (se usan mecanismos de cuenta de referencias).
Ventajas
· La separación entre interfaz e implementación permite configurar (y cambiar) esta
relación dinámicamente, en tiempo de ejecución (y no de compilación). Además, esta
independencia favorece una mejor estructuración en niveles del sistema.
· La citada independencia de variación repercute en una mayor extensibilidad.
· Se favorece el encapsulamiento, al ocultarse a los clientes detalles referentes a la
implementación, como la compartición de implementaciones, por ejemplo.
Relacionado con
· Fábrica Abstracta puede servir para crear y configurar un Puente en concreto.
· Adaptador trabaja con sistemas ya diseñados, tratando de hacer compatibles
clases con diferentes interfaces, mientras que Puente realiza su misión durante la fase de
diseño, posibilitando que abstracciones e implementaciones varíen independientemente.
Otros aspectos de interés
· Al contrario que Adaptador, Puente no puede construirse usando herencia múltiple
(pública para la interfaz y privada para la implementación) porque esto ligaría de forma
permanente una implementación a una abstracción (al menos en C++, que tiene herencia
estática).
· “Abstracción” puede conocer todas las “ImplementacionesConcretas” y elegir una
o puede tener una por defecto o puede delegar la decisión en una Fábrica Abstracta.
· Si sólo hay una implementación, la clase base de la jerarquía de
implementaciones puede no ser necesaria, pero la separación entre abstracción e
implementación sí, porque garantiza la independencia.
________________________________________________________________________________
- 47 -
Colección de patrones Banda de los Cuatro
Ejemplo de aplicación
En una Interfaz Gráfica de Usuario (GUI) lo normal es tratar de permitir que los
distintos elementos gráficos (una ventana, por ejemplo) se adapten a los diferentes
contextos en que deben ser usados y a las diferentes plataformas hardware sobre las que
pueden funcionar. Así, no será lo mismo una ventana en el sistema Xwindows que en el
sistema Presentation Manager (PM). Y siempre podemos querer especializar el elemento
gráfico genérico (la ventana) para adecuarnos mejor a ciertas circunstancias concretas
(no es lo mismo una ventana para albergar iconos que una ventana temporal, para
acontecimientos transitorios como una ayuda en línea o una solicitud de introducción de
datos por el usuario). Por tanto, puede ser de mucha utilidad (sobre todo pensando en
futuras ampliaciones) separar los aspectos de interfaz de los de implementación.
puente
imp
VENTANA IMPLEMENTACIÓN DE
VENTANA
DibujarTexto()
DibujarCuadro() ImplementaDibujarTexto()
ImplementaDibujarLinea()
imp->ImplementaDibujarLinea();
VENTANA PARA imp->ImplementaDibujarLinea();
ICONOS imp->ImplementaDibujarLinea();
imp->ImplementaDibujarLinea();
DibujarBorde()
IMPLEMENTACIÓN DE IMPLEMENTACIÓN DE
VENTANA XWINDOW VENTANA PM
ImplementaDibujarTexto()
ImplementaDibujarLinea()
DibujarCuadro(); ImplementaDibujarTexto()
DibujarTexto(); ImplementaDibujarLinea() XDibujarTexto();
XDibujarLinea();
RECUERDO / MEMENTO
Tipo
Comportamiento, a nivel de objetos.
Propósito
Capturar y exteriorizar el estado interno de un objeto, sin violar el encapsulamiento,
para que dicho objeto pueda restaurar este estado en el futuro, si lo desea.
Estructura
recuerdo
ORIGINADOR RECUERDO CUIDADOR
________________________________________________________________________________
- 48 -
Colección de patrones Banda de los Cuatro
ObtenerEstado()
FijarEstado()
FijarRecuerdo(Recuerdo r)
CrearRecuerdo() estado
Cuando usarlo
· Cuando sea necesario registrar una “instantánea” (o parte de ella) del estado
interno de un objeto para permitir posteriores restauraciones de dicho estado registrado y,
además, exista el peligro de que una interfaz directa, “abierta” sobre el propio objeto,
pueda exponer detalles de implementación del mismo, rompiendo así el encapsulamiento.
Ventajas
· Se salvaguarda el encapsulamiento, impidiendo la exposición pública de
información que sólo el “Originador” debe manejar, pero que, por otra parte, puede (y
debe) almacenarse fuera del mismo.
· Se simplifica al objeto “Originador”, que en otros diseños posibles, que también
preservarían el encapsulamiento, tendría que hacerse cargo del mantenimiento de todas
las versiones del estado interno en que los clientes estuvieran interesados.
Inconvenientes
· El uso de “Recuerdos” puede convertirse en inapropiado, por el excesivo consumo
de recursos, en el caso de que la información que el “Originador” deba almacenar en el
“Recuerdo” sea considerable o las peticiones de los clientes solicitando “Recuerdos” sea
demasiado frecuente.
· Puede resultar problemático en ciertos lenguajes el mantenimiento de dos
interfaces distintas (“amplia” para el “Originador” y “estrecha” para el “Cuidador”) para
acceder al “Recuerdo”.
· Puede haber costes ocultos en el cuidado de los “Recuerdos”, pues los
“Cuidadores” son los responsables de eliminar los “Recuerdos” que vigilan, pese a no
conocer sus interioridades, lo cual dificulta su labor.
Relacionado con
· Acción puede usar Recuerdo para mantener el estado en aquellas operaciones
que se pueden “deshacer” (cambios de estado incrementales).
· Iterador puede ser sustituido o implementado en términos de Recuerdo, dado que
una interfaz para iteraciones basada en “Recuerdos” permite que más de una iteración se
haga simultánea o solapadamente (cosa que ya permite Iterador) y además no rompe el
encapsulamiento de la colección que se recorre (el “Recuerdo” sólo es interpretada por la
propia colección de objetos que se recorre, nadie más tiene acceso a ella).
Ejemplo de aplicación
En un editor gráfico podemos tener elementos como cajas o recuadros que se
pueden conectar entre si por medio de flechas o lineas discontinuas. Existe la posibilidad
de mover de posición todo (o partes de) un dibujo, siendo requisito indispensable que las
relaciones entre los distintos elementos del mismo se mantengan, a pesar de variar su
situación en el documento. Más aún es deseable que un traslado de elementos de un
dibujo pueda ser deshecho fácilmente y con total eficiencia, esto es, que todo quede como
al principio. Por lo general, las relaciones espaciales entre estos elementos se mantienen
y resuelven con un sistema de resolución de restricciones, que puede almacenar en un
objeto aparte su estado en un momento determinado, para poder así restaurarlo cuando
la operación que lo sacó de él sea deshecha o anulada por el usuario.
recuerdo
RESOLUTOR DE ESTADO DEL RESOLUTOR EDITOR
RESTRICCIONES sol
ObtenerEstado()
FijarEstado()
FijarRecuerdo(Recuerdo r) estado
HacerMover()
CrearRecuerdo() DeshacerMover()
estado
return new Recuerdo(estado); estado = r -> ObtenerEstado(); recuerdo = sol -> CrearRecuerdo();
sol -> Mover(+posición);
sol -> ResolverRestricciones();
Tipo
Creación, a nivel de objetos.
Propósito
Garantizar que una clase sólo tiene una única instancia, proporcionando un punto
de acceso global a la misma.
Estructura
SOLITARIO
return InstanciaÚnica;
static Instancia()
OperaciónDelSolitario()
ObtenerDatosDelSolitario()
________________________________________________________________________________
- 50 -
Colección de patrones Banda de los Cuatro
static InstanciaÚnica
DatosDelSolitario
Cuando usarlo
· Cuando debe haber únicamente una instancia de una clase y debe ser claro su
acceso para los clientes.
· Cuando la “InstanciaÚnica” debe ser especializable mediante herencia y los
clientes deben poder usar la instancia extendida sin modificar su código (el de los
clientes).
Ventajas
· El acceso a la “InstanciaÚnica” está más controlado.
· Se reduce el espacio de nombres (frente al uso de variables globales).
· Permite refinamientos en las operaciones y en la representación, mediante la
especialización por herencia de “Solitario”.
· Es fácilmente modificable para permitir más de una instancia y, en general, para
controlar el número de las mismas (incluso si es variable).
· Es más flexible que la alternativa de las “operaciones de clase”, además de que
éstas (en C++), al ser funciones miembro estáticas, no son virtuales, luego no pueden ser
especializadas mediante herencia ni redefinidas polimórficamente.
Relacionado con
· Muchos otros patrones pueden implementarse haciendo uso de Solitario. Por
ejemplo : Fábrica Abstracta, Constructor y Prototipo.
Ejemplo de aplicación
Son numerosos los ejemplos de clases de objetos que deben tener una única
instancia. Así, aunque un sistema tenga muchas impresoras, debe haber sólo un
“spooler”. Debe haber, también, un único sistema de ficheros y un único gestor del
sistema de ventanas. Un filtro digital tendrá sólo un conversor A/D. Tomemos este último
como ejemplo :
Filtrar()
public : if (InstanciaÚnica == 0)
static Conversor* Instancia() InstanciaÚnica = new Conversor;
protected : return InstanciaÚnica;
Conversor()
private :
static Conversor* InstanciaÚnica
________________________________________________________________________________
- 51 -
Colección de patrones Banda de los Cuatro
····
conv = conversor -> Instancia();
conv.Convertir();
····
________________________________________________________________________________
- 52 -
Colección de patrones Banda de los Cuatro
VISITANTE / VISITOR
Tipo
Comportamiento, a nivel de objetos.
Propósito
Representar una operación que está pensada para ser aplicada sobre los
elementos de una estructura de objetos, permitiendo así definir y añadir un nuevo
comportamiento sin necesidad de cambiar las clases de los elementos de la estructura de
objetos.
Estructura
ELEMENTO CLIENTE VISITANTE
Aceptar(Visitante) VisitarElementoA(ElementoA)
VisitarElementoB(ElementoB)
ESTRUCTURA
DE OBJETOS
v->VisitarElementoA(this); v->VisitarElementoB(this);
Cuando usarlo
· Cuando una “Estructura De Objetos” contiene muchas clases con diferentes
interfaces y se quieren añadir operaciones a dichos objetos en función de la interfaz.
· Cuando se quieren añadir a los objetos de una estructura operaciones muy
diferentes y sin relación alguna entre ellas, sin necesidad de hacerlo a nivel individual.
· Cuando las clases que definen la “Estructura De Objetos” casi nunca cambian,
pero frecuentemente queremos añadir nuevas operaciones a ciertos objetos de la
estructura.
Ventajas
· Es fácil añadir nuevas operaciones a la “Estructura De Objetos”; sólo hay que
crear un nuevo “Visitante”, en vez de cambiar todas las clases a las que queremos que
afecte.
· Se juntan las operaciones relacionadas entre sí, separándose las que nada tienen
que ver. Esto simplifica tanto las clases de los “Elementos” como los algoritmos definidos
en los “Visitantes”.
· Se pueden recorrer jerarquías formadas por objetos de distintos tipos (distinta
clase padre), mientras que un Iterador no puede hacer esto.
· Se puede ir acumulando el estado a medida que se recorre la estructura, en vez
de tener que pasarlo como parámetro o guardarlo en variables globales.
Inconvenientes
________________________________________________________________________________
- 53 -
Colección de patrones Banda de los Cuatro
Relacionado con
· Visitante puede usarse para aplicar una operación sobre una estructura de objetos
definida por Composición.
· Visitante puede utilizarse para implementar la operación de interpretación en el
patrón Intérprete.
Ejemplo de aplicación
En un compilador que representa los programas mediante árboles sintácticos
abstractos es mejor tener por un lado la jerarquía de nodos (declaraciones de asignación,
acceso a variables, expresiones aritméticas, etc ... ) y por otro las operaciones que
queremos aplicarles (comprobación de tipos, generación de código, análisis de flujo,
optimizaciones, etc ... ) que tener todas las operaciones dentro de cada nodo, dado que
no a todos los nodos les afectan igual las distintas operaciones.
Aceptar(VisitanteDeNodo) VisitarAsignación(NodoAsignación)
VisitarVariable(NodoVariable)
PROGRAMA
v->VisitarAsignación(this); v->VisitarVariable(this);
________________________________________________________________________________
- 54 -