You are on page 1of 57

Unidad Docente de Ingeniería del Software

Facultad de informática - Universidad Politécnica de Madrid


Índice
ACCIÓN / COMMAND.....................................................................................................................................1

ADAPTADOR / ADAPTER...............................................................................................................................6

APODERADO / PROXY ...................................................................................................................................7

CADENA DE RESPONSABILIDADES / CHAIN OF RESPONSIBILITY...............................................11

COMPOSICIÓN / COMPOSITE ...................................................................................................................14

CONSTRUCTOR / BUILDER ........................................................................................................................15

DECORADOR / DECORATOR .....................................................................................................................19

ESTADO / STATE............................................................................................................................................21

ESTRATEGIA / STRATEGY .........................................................................................................................22

FÁBRICA ABSTRACTA / ABSTRACT FACTORY ...................................................................................25

FACHADA / FACADE.....................................................................................................................................26

INTÉRPRETE / INTERPRETER...................................................................................................................28

ITERADOR / ITERATOR...............................................................................................................................32

MEDIADOR / MEDIATOR ............................................................................................................................34

MÉTODO DE FÁBRICA / FACTORY METHOD.......................................................................................35

MÉTODO PLANTILLA / TEMPLATE METHOD .....................................................................................37

OBSERVADOR / OBSERVER .......................................................................................................................41

PESO MOSCA / FLYWEIGHT ......................................................................................................................42

PROTOTIPO / PROTOTYPE.........................................................................................................................44

PUENTE / BRIDGE .........................................................................................................................................46

RECUERDO / MEMENTO .............................................................................................................................48

________________________________________________________________________________
-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:

APLICACIÓ MENÚ ENTRADA


N
Añadir(doc) Añadir(entr) Seleccionar()

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:

doc:Documento m:Menú e_a:Entrada_Abrir ap:Aplicación

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();

Para el caso de los botones el escenario es similar:

doc:Documento b:Barra b_a:Botón_Abrir ap:Aplicación

new Botón_Abrir(b_a)
Añadir(b_a)

Presionar()
new Documento(doc)
Añadir(doc)
Abrir()

El problema de esta solución es que se duplica la implementación de la operación que


ejecutan tanto la entrada de menú como el botón. El hecho de que existan dos o más
alternativas para acceder a una misma función de la aplicación (algo positivo, en principio)
no debe traducirse en redundancia a la hora de implantar dicha función (algo negativo, por
el desperdicio de recursos que ello implica).

________________________________________________________________________________
-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:

APLICACIÓ MENÚ ENTRADA acción acción


N
Añadir(doc) Añadir(entr) AsignarAcc() BARRA
Seleccionar()
Añadir(bot)
ACCIÓN
Ejecutar()
acción->Ejecutar()

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()

Los escenarios siguientes representan, respectivamente, la creación y posterior


asignación de una nueva acción a una entrada de menú y un botón, así como la ejecución
de dicha acción mediante la selección de ambos elementos gráficos:

bot:Botón ent:Entrada acción:Abrir ap:Aplicación

new Abrir(acción)
AsignarAcc(acción)
AsignarAcc(acción)

doc:Documento ent:Entrada acción:Abrir ap:Aplicación

Ejecutar()
Seleccionar()
new Documento(doc)
Añadir(doc)

Abrir()

doc:Documento bot:Botón acción:Abrir ap:Aplicación

Ejecutar()
Presionar()
new Documento(doc)
Añadir(doc)
Abrir()

Solución
________________________________________________________________________________
-3-
Colección de patrones Banda de los Cuatro

Encapsular en un objeto la acción que satisface una petición.

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

PETICIONARIO acción ACCIÓN


AsignarAcción()
AtenderPetición() Ejecutar()
acción->Ejecutar()

RECEPTOR

Operación() receptor ACCIÓN CONCRETA

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.

Otros aspectos de interés


· El “Cliente” es el responsable de crear la “AcciónConcreta” correspondiente a una
petición y de configurarla con el “Receptor” que sabe resolverla.
· “Acción” suele ser una clase abstracta que define la interfaz para la ejecución de
operaciones.
· Para dar soporte a operaciones que se puedan deshacer y/o rehacer es preciso
almacenar la información de estado que permita hacerlo y si además se pretende hacer
esto en múltiples niveles habrá que mantener una “lista de históricos” con las acciones ya
ejecutadas.
· Cada “AcciónConcreta” establece una relación entre el receptor de la petición y la
acción que éste realiza para satisfacerla.
· Para permitir deshacer y/o rehacer operaciones, el “estado” debe contener
información relativa a los receptores, las acciones y las operaciones involucradas en el
proceso.
· Las habilidades de cada “AcciónConcreta” van desde la simple invocación de la
correspondiente “Operación” del “Receptor” hasta la implementación interna de toda la
acción que satisface la petición.

________________________________________________________________________________
-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

A nivel de clases ...

OBJETIVO CLASE A ADAPTAR


CLIENTE
Petición() PeticiónConcreta()

ADAPTADOR

Petición()
PeticiónConcreta()

A nivel de objetos ...

OBJETIVO CLASE A ADAPTAR


CLIENTE
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

· Facilidad para redefinir el comportamiento de la clase adaptada.


· Simplicidad (un sólo objeto, no hay punteros ni indirecciones adicionales).
A nivel de objetos ...
· Flexibilidad para que un sólo adaptador trabaje con muchas clases a adaptar (en
concreto, puede hacerlo con toda una jerarquía de clases).
· Extensibilidad, puesto que se pueden añadir funcionalidades a todas las clases
adaptadas a la vez.

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.

Otros aspectos de interés


· En el adaptador a nivel de clase, “adaptador” hereda públicamente la interfaz de
“objetivo” y privadamente la implementación de la “clase a adaptar”.
· Un “adaptador enchufable” es una clase que tiene ya definidas internamente las
posibles adaptaciones de su interfaz.
· Los “adaptadores de doble sentido” sirven para obtener transparencia ante
diferentes clientes.
· ¡El adaptador a nivel de objeto requiere un poco más de esfuerzo que el
adaptador a nivel de clase, pero, a la larga, resulta más flexible!

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).

FORMA VISTA DE UN TEXTO


EDITOR GRAFICO
Contorno() ObtenerExtensión()

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

Estructura, a nivel de objetos.

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()

ELEMENTO REAL APODERADO


············
Petición() Elemento Petición() ElementoReal -> Petición()
Real ············

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

· Decorador puede tener una implementación similar a la de Apoderado, a pesar de


tener una intención diferente : añadir algún comportamiento a un objeto, en vez de
controlar el acceso al mismo. Diferentes apoderados varían en el grado de semejanza en
su implementación con respecto a Decorador.

Otros aspectos de interés


· El “Apoderado” es el encargado de crear y destruir los “Elementos Reales” cuando
haga falta.
· Si el “Apoderado” puede tratar con el “Elemento Real” a través de una interfaz
abstracta, entonces no es necesario tener una clase “Apoderado” por cada clase de
“Elemento Real”. Pero si el “Apoderado” va a ser instanciado con un “Elemento Real”
concreto, debe conocer de que clase es.
· Para poder representar al “Elemento Real”, el “Apoderado” debe tener una interfaz
idéntica a la de “Elemento”.
· Una cuestión importante es : ¿cómo hacer referencia al “representado” antes de
instanciarlo?
· Un apoderado remoto debe responsabilizarse de empaquetar y enviar las
peticiones y sus argumentos al objeto real.
· Un apoderado virtual puede almacenar información adicional relativa al objeto
para posponer el acceso al mismo.
· Tanto un apoderado de protección como una referencia “inteligente” comprueban
los permisos de acceso del cliente antes de pasar la petición al objeto.

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

CADENA DE RESPONSABILIDADES / CHAIN OF RESPONSIBILITY

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()

RESPONSABLE CONCRETO 1 RESPONSABLE CONCRETO 2

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

· Muchas personas ven Cadena de Responsabilidades como una Estrategia


“recursiva” o “distribuida”, donde el segundo encapsula unos algoritmos y el primero el
criterio necesario para seleccionar un algoritmo concreto. Parece ser (se trata de una
cuestión de interpretaciones y, por tanto, abierta) que una Estrategia “recursiva” es una
Cadena de Responsabilidades, pero no al revés, porque los “Responsables” de ésta
última pueden hacer más cosas aparte de encapsular un algoritmo, que es la única misión
de la primera.

Otros aspectos de interés


· Todos los “Responsables” en la cadena comparten una interfaz común, para
garantizar la transparencia que nos permite evitar el acoplamiento.
· El “Responsable” padre de todos los “Responsables Concretos” puede,
opcionalmente, implementar el enlace al sucesor, para que no tengan que hacerlo sus
hijos o para ofrecer un mismo tipo de enlace a todos ellos (aunque pueden redefinirlo).
· En función de las circunstancias, se pueden aprovechar enlaces preexistentes
entre objetos para implementar el enlace al sucesor o se pueden definir otros nuevos.
· Puede haber un conjunto fijo e inflexible de peticiones que los “Responsables”
atienden, lo cual aumenta la sencillez y seguridad del sistema, o se puede permitir una
mayor flexibilidad en el tipo de peticiones mediante PARAMETRIZACIÓN, siempre y
cuando el cliente y los manejadores se pongan de acuerdo acerca del número, tipo y
significado de los parámetros.

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()

APLICACIÓN ELEMENTO GRÁFICO

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

· PesoMosca permite la compartición de componentes, pero presenta problemas a


la hora de hacer referencia a los padres (ambigüedad por tener un componente varios
padres).
· Iterador se usa para recorrer jerarquías de composición recursiva.
· Visitante localiza operaciones y comportamientos que de otro modo estarían
dispersos entre las clases “Simple” y “Compuesto”.

Otros aspectos de interés


· El cliente sólo trata con un componente genérico, no pudiendo, por tanto,
distinguir si es simple o compuesto.
· “Componente” puede tener algún mecanismo para acceder al padre en la
jerarquía de cada objeto (necesario para Cadena de Responsabilidades).
· Cuanto mayor sea la interfaz de “Componente” mayor será la uniformidad
(=transparencia) con la que el cliente trata a los distintos elementos, pero eso tiene el
inconveniente de que un elemento simple hereda operaciones que sólo tienen sentido
para elementos compuestos.
· Si las operaciones de gestión de los “hijos” (Poner, Quitar, etc ...) se ponen en
“Componente” prima la TRANSPARENCIA sobre la SEGURIDAD. Si se ponen en
“Compuesto” sucede al contrario.
· La estructura de datos utilizada para representar a los “hijos” depende de las
circunstancias de cada caso, siempre en aras de la EFICIENCIA (ver Intérprete).
· Si los “hijos” están ordenados de alguna forma, el acceso y la gestión de los
mismos debe ser especialmente cuidadosa (ver Iterador). Además, salvo en lenguajes
con recolección de basura, la eliminación de los “hijos” es tarea del padre.

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

Dibujar() Dibujar() Dibujar() para todos los componentes


Dibujar() c.Dibujar();
ObtenerHijo(int)
Quitar(Componente)
Añadir(Componente c)
añadir c a la lista de
CONSTRUCTOR / BUILDER componentes;

________________________________________________________________________________
- 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()

para todos los objetos de la estructura


{constructor->ConstruirParte();}
CONSTRUCTOR CONCRETO

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

objetos (simples o complejos). Además, en el primero el resultado se obtiene en el último


paso y en el segundo se obtiene inmediatamente.
· Las estructuras de los objetos complejos que crea este patrón nos llevan
frecuentemente al patrón Composición.

Otros aspectos de interés


· “Constructor” suele ser una clase abstracta, por lo que “ConstruirParte” es una
operación abstracta; en concreto, una por cada tipo de parte del objeto complejo. ¡En
C++, suelen ser métodos vacíos, no virtuales puros!
· En general no tiene sentido contemplar una clase abstracta de productos, dada la
heterogeneidad de los mismos.
· La operación “Construir”, por lo general, es una sucesión de peticiones de
construcción de partes, pero, a veces, es necesario acceder a partes de la estructura ya
construidas (o acciones similares).
· La función “ObtenerResultado” es de suma importancia, ya que a través de ella el
“Director” puede conseguir el producto final, una vez construidas todas sus partes y
ensambladas.

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()

CONVERSOR A ASCII CONVERSOR A TEX


while (t = siguiente token)
{ ConvertirCarácter(char) ConvertirCarácter(char)
switch t.Tipo ObtenerTextoEnAscii() ConvertirCambioDeFuente(fuente)
{ ConvertirParrafo()
CHAR : ObtenerTextoEnTEX()
constructor->ConvertirCaracter(t.Char);
FUENTE : CONVERSOR A ELEMENTOS
constructor->ConvertirCambio GRÁFICOS DE TEXTO
DeFuente(t.Fuente);
ConvertirCarácter(char)
PÁRRAFO :
ConvertirCambioDeFuente(fuente)
constructor->ConvertirParrafo();
ConvertirParrafo()
}
ObtenerElementoGráficoDeTexto()
}

Texto en Ascii Elemento Gráfico de Texto Texto en TEX

________________________________________________________________________________
- 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()

COMPONENTE CONCRETO DECORADOR


componente
Operación() Operación()
componente -> Operación;

Decorador::Operación();
Comportamiento();

DECORADOR CONCRETO A DECORADOR CONCRETO B

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

· Gran fragmentación5; el sistema se llena de gran cantidad de objetos pequeños, lo


cual puede dificultar el aprendizaje de su funcionamiento y su depuración, aunque el que
lo domine puede adaptarlo fácilmente.

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.

Otros aspectos de interés


· “Componente” debe permanecer lo más “ligera” posible, definiendo una interfaz
genérica y simple, para no arrastrar hacia complejidades innecesarias a “Componentes
Concretos” y “Decoradores” (ver Composición).
· Un Decorador puede convertirse en una solución muy costosa si los componentes
son, por naturaleza, muy complejos. En esos casos es preferible Estrategia.
· Puede resultar problemático especializar mediante herencia los “Componentes
Concretos”, por culpa de la coherencia que el “Decorador” debe guardar, en cuanto a
interfaz se refiere, con la clase base (“Componente”).

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()

VISTA DE UN TEXTO DECORADOR


componente
Dibujar() Dibujar()
componente -> Dibujar();

Decorador::Dibujar();
DibujarBorde();

BORDE BARRA DE DESPLAZAMIENTO

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()

ESTADO CONCRETO A ESTADO CONCRETO B

estado -> Atender(); Atender() 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

· PesoMosca explica como los objetos Estado pueden ser compartidos.


· Los objetos Estado a menudo son Solitarios.

Otros aspectos de interés


· La misión de “Contexto” es definir la interfaz que interesa a los clientes, mientras
mantiene una referencia al “Estado” actual. Si dicho “Estado” necesita tener acceso al
“Contexto” al que está asociado, éste puede pasarse a si mismo como parámetro de la
petición.
· Si los estados que van a hacer falta no se conocen “a priori” y el “Contexto”
cambia de “Estado” poco frecuentemente, es mejor ir creando/destruyendo estados sobre
la marcha. Pero si el “Contexto” cambia constantemente de “Estado” es preferible crear
todos los estados al comienzo y no destruirlos nunca (pueden volver a hacer falta).
· Las transiciones entre estados pueden estar prefijadas “a priori” en el “Contexto” o
pueden dejarse a la responsabilidad de cada estado, que tendrá entonces que saber
quien le “sucede” (aparte de este inconveniente, esta solución es más flexible y, por ello,
preferible). Otra alternativa es una transición entre estados definida tabularmente. Esto
permite cambiar el criterio de transición cambiando solamente los datos de entrada, pero
es menos eficiente, hace menos explícitas las transiciones entre estados y dificulta el
añadir acciones a dichas transiciones7.
· Algunos lenguajes (Self) permiten a un objeto cambiar de clase en tiempo de
ejecución, en lo que constituye una especie de herencia dinámica; esto es, soportan
directamente este patrón.

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...

CONEXIÓN_TCP estado ESTADO_TCP

Abrir()
Abrir() Cerrar()
Cerrar() MandarConfirmación()
MandarConfirmación()

TCP_CONECTADO TCP_ESCUCHANDO TCP_CERRADO

Abrir() Abrir() Abrir()


estado -> Abrir(); Cerrar() Cerrar() Cerrar()
MandarConfirmación() 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()

ESTRATEGIA CONCRETA A ESTRATEGIA CONCRETO B


···············
estrategia -> InterfazDelAlgoritmo(); InterfazDelAlgoritmo() 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.

Otros aspectos de interés


· Si el “Contexto” pasa a la “Estrategia” los datos como parámetros de las
operaciones de esta última se mantiene un acoplamiento débil, pero la eficiencia se puede
resentir (puede que haya “Estrategias” que reciban datos que no necesitan). Si el
“Contexto” se pasa a sí mismo como parámetro o la “Estrategia” mantiene una referencia
al “Contexto” se resuelve este último problema a cambio de un mayor acoplamiento.
· Los clientes configuran al “Contexto” con una “Estrategia” determinada, con la
cual el “Contexto” interactúa para producir un comportamiento determinado. Para tal fin,
el “Contexto” puede definir una interfaz que permita a la “Estrategia” acceder a sus datos
internos.
· Existe la posibilidad de que el “Contexto” defina un comportamiento por defecto y
sólo en el caso de que los clientes deseen otra cosa se le configure con la “Estrategia”
correspondiente.
· En C++, en el caso de que la “Estrategia” se fije en tiempo de compilación y se
vaya a cambiar en ejecución se pueden usar plantillas (templates) para configurar un
“Contexto” con una “Estrategia”.

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()
···············

ALGORITMO TEX ALGORITMO SIMPLE ALGORITMO MATRICIAL

DividirEnLineas() DividirEnLineas() DividirEnLineas()

________________________________________________________________________________
- 24 -
Colección de patrones Banda de los Cuatro

FÁBRICA ABSTRACTA / ABSTRACT FACTORY

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

PRODUCTO-A2 PRODUCTO-A1 PRODUCTO-B2 PRODUCTO-B1

FABRICA ABSTRACTA

CrearProductoA()
CrearProductoB()

FABRICA CONCRETA 1 FABRICA CONCRETA 2

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

· Se potencia el encapsulamiento, puesto que se aísla a los clientes de las


implementaciones.
· Se incrementa la flexibilidad del diseño, resultando fácil cambiar de familia de
productos (recordemos que actúa toda junta).
· Se refuerza la consistencia, puesto que se restringe el uso a productos de una
sola familia cada vez.

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.

Otros aspectos de interés


· “FábricaAbstracta” no suele ser una clase abstracta en realidad, sino que,
generalmente, proporciona una implementación básica o estándar de las operaciones,
que será redefinida a voluntad por sus subclases.

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.

VENTANA CLIENTE BARRA DE DESPLAZAMIENTO

VENTANA MOTIF VENTANA PM BARRA MOTIF BARRA PM

FABRICA DE ELEMENTOS GRÁFICOS

CrearBarraDeDesplazamiento()
CrearVentana()

FABRICA DE ELEMENTOS PM FABRICA DE ELEMENTOS MOTIF

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

Cliente1 Cliente2 Cliente3 Cliente1 Cliente2 Cliente3

FACHADA

Clase1 del Clase2 del Clase1 del Clase2 del


subsistema subsistema subsistema subsistema

Clase3 del Clase4 del Clase3 del Clase4 del


subsistema subsistema subsistema subsistema

Clase5 del Clase5 del


subsistema SUBSISTEMA subsistema SUBSISTEMA
DE CLASES DE CLASES

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

· Fábrica Abstracta puede usarse conjuntamente con Fachada para proporcionar


una interfaz que permita crear objetos del subsistema de manera independiente a éste.
Además, puede ser una alternativa para ocultar las clases específicas de una plataforma.
· Mediador es similar a Fachada pues también abstrae la funcionalidad de clases ya
existentes, pero está orientado a la comunicación entre objetos “colegas” y además suele
centralizar aquellas responsabilidades que no competen a ninguno de ellos. Por su parte,
como hemos visto, Fachada abstrae la interfaz de un subsistema para facilitar su uso, sin
añadir funcionalidades y resultando transparente a éste.
· Lo más frecuente es que sólo haya un objeto Fachada de cada tipo. De ahí su
relación con Solitario.

Otros aspectos de interés


· La “Fachada” sabe qué clase es responsable de cada petición, pero es
completamente transparente para ellas. Por tanto, aunque las funciones las desempeñan
las otras clases, es a la “Fachada” a quien le toca el trabajo de “traducir”.
· Una manera de reducir el acoplamiento es hacer abstracta la “Fachada” y luego
especializar mediante herencia. Otra posibilidad es configurar la “Fachada” con objetos
del subsistema, que pueden cambiarse. Esta posibilidad puede entrar en conflicto con el
objetivo de la “Fachada”, la facilidad de uso.
· Un subsistema es análogo a una clase, en el sentido de que tiene una interfaz
PÚBLICA (de la que forma parte la “Fachada”) y otra PRIVADA (¡que no está muy claro
como conseguirla ni para que sirve!).

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

CLIENTE EXPRESIÓN ABSTRACTA

Interpretar(contexto)

CONTEXTO EXPRESIÓN TERMINAL EXPRESIÓN NO TERMINAL

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.

Otros aspectos de interés


· Si un tipo particular de problemas se presenta frecuentemente, puede ser
provechoso expresar los diferentes casos del problema como sentencias de un lenguaje
simple. Se puede, entonces, construir un intérprete que resuelva el problema
interpretando dichas sentencias.
· Si es frecuente la creación de nuevos intérpretes o de nuevas formas de
“interpretar” es mejor tener un Visitante, donde poner la operación a realizar fuera de la
estructura de árbol.
· El “Cliente” construye (o recibe) una estructura de instancias de “Expresiones
terminales” y “Expresiones no terminales”, ensambladas para formar un árbol sintáctico
que representa la sentencia que se quiere interpretar, mientras que el “Contexto” contiene
información global para el intérprete.
· A pesar de la similitud de la estructura de este patrón con la del patrón
Composición hay sus diferencias, como que al Intérprete no le interesa como se construye
el árbol sintáctico (eso es cosa del “Cliente” o de quien sea).
· Aunque la operación “estrella” es “Interpretar”, un Intérprete puede ser utilizado
para realizar otra serie de operaciones sobre las sentencias de un lenguaje.

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 :: = literal | alternativa | secuencia | repetición


literal :: = ‘a’ | ‘b’ | ‘c’ | ... {‘a’ | ‘b’ | ‘c’ | ... } *
alternativa :: = expresión ‘|’ expresión
secuencia :: = expresión ‘&’ expresión
repetición :: = expresión ‘*’

________________________________________________________________________________
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()

AGREGADO CONCRETO ITERADOR CONCRETO

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.

Otros aspectos de interés


· Cuando el “Cliente” controla la iteración se dice que el “Iterador” es externo y
cuando la controla el propio “Iterador” se dice que es interno. Los “Iteradores” externos
son más flexibles y potentes, mientras que los internos son más sencillos de usar. Los
“Iteradores” externos son problemáticos con estructuras recursivas como las de
Composición (se suelen usar entonces “Iteradores Nulos”).
· Si el algoritmo para recorrer la estructura lo proporciona el agregado, el “Iterador”
sólo guarda el estado y se le llama CURSOR (ver Recuerdo). Si el algoritmo reside en el
propio “Iterador” es más fácil usar el mismo sobre estructuras diferentes o diferentes
algoritmos sobre la misma estructura, puede violarse el encapsulamiento, por necesidad
de acceder a variables privadas de la estructura.
· Dada la estrecha relación entre el “Agregado” y el “Iterador” éste puede ser una
“clase amiga” de aquel, sin necesidad de sobrecargar la interfaz de dicho “Agregado”.
· Un “Iterador” robusto no debe verse afectado por altas y bajas en los elementos
de estructura que recorre ni necesitar hacer una copia de la misma cada vez que ésta se
modifica (¡que los cambios se reflejen en el estado del “Iterador”!).
· Cada “AgregadoConcreto” es el encargado de crear el “Iterador Concreto” que se
adapta a su estructura concreta (ver Método de Fábrica).

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.

LISTA ABSTRACTA ITERADOR


CLIENTE
CrearIterador() Primero()
Contar() Siguiente()
Añadir(elemento) Actual()
Eliminar(elemento) SeLlegoAlFinal()
...

LISTA NORMAL ITERADOR NORMAL

LISTA SKIP ITERADOR SKIP

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

MEDIADOR COLABORADOR COLABORADOR


CONCRETO 1 CONCRETO 2
CONCRETO

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

· Se cambia complejidad en la interacción por complejidad en el “Mediador”, que se


puede convertir en el elemento más complejo del conjunto de objetos. Este carácter
monolítico lo hará difícil de mantener11.

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.

Otros aspectos de interés


· Si los “Colaboradores” sólo trabajan con un “MediadorConcreto”, entonces el
“Mediador” abstracto y general sobra, pues es el propósito del acoplamiento abstracto que
con él se plantea es, precisamente, permitir trabajar con varios “Mediadores” diferentes.
· Una posibilidad para implementar los “MediadoresConcretos” es usar el patrón
Observador; otra, definir en el “Mediador” una interfaz de notificación especializada, que
permita al objeto identificarse cuando se comunica con el “Mediador”.
· Cuanto más compleja sea la estructura de objetos que pone en comunicación el
“Mediador”, menores serán los beneficios que podrá proporcionar.

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

MÉTODO DE FÁBRICA / FACTORY METHOD

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();
···

PRODUCTO CONCRETO CREADOR CONCRETO

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.

Otros aspectos de interés


· “MétodoFábrica” puede ser algo más que una mera declaración del método,
puede tener una implementación genérica, por defecto. En C++, es un método virtual,
generalmente puro.
· Parametrizando “MétodoFábrica” con el tipo del producto a crear nos ahorramos
las subclases de “Creador” (también se pueden usar templates, en C++).
· La filosofía que sigue el “Creador” es de INICIALIZACIÓN PEREZOSA, ya que, al
acceder al producto, si no existe todavía, se crea.

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();

DOCUMENTO GRÁFICO APLICACIÓN GRÁFICA

CrearDocumento()
return new DocumentoGráfico;

MÉTODO PLANTILLA / TEMPLATE METHOD


Tipo
Comportamiento, a nivel de clases.

Propósito

________________________________________________________________________________
- 37 -
Colección de patrones Banda de los Cuatro

Definir el esqueleto de un algoritmo para una operación, dejando para sus


subclases la capacidad de redefinir el funcionamiento de los pasos de este algoritmo,
siempre y cuando la estructura del mismo permanezca intacta.

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

· La diferencia entre Método Plantilla y Estrategia es que el primero usa la herencia


para variar parte de un algoritmo mientras el segundo usa la delegación para variar
completamente un algoritmo.

Otros aspectos de interés


· La “ClaseAbstracta” define el “MétodoPlantilla” (que define un algoritmo en
términos de operaciones abstractas) mientras que la “ClaseConcreta” implementa las
“OperacionesPrimitivas” (esto es, redefine las operaciones abstractas en sus homónimas
concretas) que dotan al algoritmo de un comportamiento concreto.
· Para que no pueda ser redefinido, el “MétodoPlantilla”, en C++, puede hacerse
función miembro virtual.
· Si se quiere que las “OperacionesPrimitivas” sólo puedan ser invocadas por el
“MétodoPlantilla” se pueden definir como miembros protegidos. Además hay que
distinguir entre operaciones adaptables (pueden redefinirse) y operaciones abstractas
(deben redefinirse), ya que estas últimas deben hacerse virtuales puras.
· La “ClaseAbstracta” define el orden de las operaciones primitivas, pero deja a las
“ClasesConcretas” la posibilidad de redefinir su funcionamiento.
· Una forma de identificar más fácilmente las operaciones que deben poderse
redefinir es anteponerles un prefijo decidido “a priori” y que se aclaratorio : por ejemplo,
“Hacer-”.
· Un objetivo primordial es reducir al mínimo el número de operaciones primitivas
que hay que redefinir.

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.

Otros aspectos de interés


· La forma más simple de implementar las relaciones entre “Asuntos” y
“Observadores” es mantener referencias explícitas y directas, lo cual puede resultar
prohibitivo. Otra opción es utilizar una tabla “hash” que tiene el inconveniente de
complicar el acceso. Cuando la relación entre “Asuntos” y “Observadores” es compleja se
puede definir un Gestor de Cambios (ver Mediador) que mantiene las referencias entre
unos y otros, define una política de actualizaciones coherente y la pone en práctica con
cada cambio en un “Asunto” que lo requiera.
· Hay que asegurarse de que las operaciones que cursan notificaciones lo hacen
una vez que el estado es consistente después del cambio, nunca antes (ver Método
Plantilla), luego LA NOTIFICACIÓN DEBE SER SIEMPRE LO ÚLTIMO.
· Aunque es frecuente que sea un “Observador” el que origina el cambio en el
“Asunto”, dicho “Observador” se suele esperar hasta que llega la notificación del “Asunto”
para actualizar su propio estado. Si se contempla la posibilidad de observar a más de un
“Asunto”, “Actualizar” debe parametrizarse para saber a cual se refiere el cambio.
· Si la “Notificación” corre a cargo del propio “Asunto” se simplifica la tarea al
cliente, pero puede ser ineficiente (muchas actualizaciones). La opción contraria, permite
juntar en una sola varias actualizaciones, pero complica la tarea del cliente.
· Para evitar las referencias “colgadas” cuando un “Asunto” desaparece, éste debe
notificarlo a sus “Observadores” para que estos puedan inutilizar sus referencias. La
notificación puede ser muy detallada (modelo PUSH) o un simple aviso, que el
“Observador” completa pidiendo la información que le interese (modelo PULL).
· Para mejorar la eficiencia, el “Asunto” puede tener constancia de ciertos
“Observadores” interesados en ciertos eventos, avisándolos sólo a ellos cuando ocurren.
· Algunos lenguajes (Smalltalk) no permiten herencia múltiple y favorecen la unión
de “Asuntos” y “Observadores”, en lugar de separarlos en clases y objetos diferentes.

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.

ASUNTO observadores OBSERVADOR

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

FÁBRICA DE PESOS MOSCA PesosMosca PESOMOSCA

ObtenerPesoMosca(clave) Operación(EstadoExtrínseco)

Si existe PesoMosca(clave) PESOMOSCA CONCRETO PESOMOSCA CONCRETO


return PesoMoscaExistente;
NO COMPARTIBLE
en otro caso {crearlo; Operación(EstadoExtrínseco)
añadirlo al grupo; Operación(EstadoExtrínseco)
return PesoMoscaNuevo;} EstadoIntrínseco
EstadoCompleto

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.

Otros aspectos de interés


· Eliminar el “EstadoExtrínseco” de los objetos compartidos puede no reducir los
costes de almacenamiento si resultan ser tan variados como los propios objetos.
· La “FábricaDePesosMosca” es quien gestiona y controla las clases compartibles,
permitiendo a los clientes el acceso (indirecto) a las mismas. Suele usar almacenamiento
asociativo para facilitar a los clientes el acceso a los objetos compartidos de su interés (si
el nº de éstos es grande y/o variable se pueden necesitar técnicas de cuenta de
referencias o recolección de basura para eliminarlos y recuperar el espacio ocupado).
· Los “PesosMoscaConcretosNoCompartibles” en una jerarquía recursiva pueden
tener hijos que sí sean para compartir. Además tenerlos inmersos en dicha jerarquía
recursiva, junto a los que si se comparten, puede facilitar en el futuro hacerlos también a
ellos compartibles, si se considera oportuno o necesario.
· El “Cliente” proporciona a las clases compartibles el “EstadoExtrínseco” que les
falta, pero siempre a través de la “FábricaDePesosMosca”, NUNCA DIRECTAMENTE.

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

Dibujar(Contexto) Dibujar(Contexto) Dibujar(Contexto)


Intersectar(Punto,Contexto) Intersectar(Punto,Contexto) Intersectar(Punto,Contexto)

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

CLIENTE prototipo PROTOTIPO

Operación() Clonar()

p = prototipo->Clonar(); PROTOTIPO PROTOTIPO


CONCRETO 1 CONCRETO 2
Clonar() Clonar()
return return
(copia de si mismo); (copia de si mismo);

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.

Otros aspectos de interés


· La operación “Clonar” puede ser conflictiva, pues el constructor que se utilice para
hacer la copia debe asegurar la independencia total con respecto al original (esto incluye
el no compartir estructuras, por ejemplo).
· “Prototipo” puede requerir una operación para inicializar.

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.

HERRAMIENTA prototipo ELEMENTO GRÁFICO

Manipular() Dibujar(posición)
Clonar()

HERRAMIENTA GRÁFICA PENTAGRAMA NOTA PENTAGRAMA

Manipular() Dibujar(posición) Dibujar(posición) Dibujar(posición)


Clonar() Clonar() 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

Operación() CLIENTE 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

estado = r -> ObtenerEstado();


estado

return new Recuerdo(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).

Otros aspectos de interés


· El “Recuerdo” tiene dos interfaces distintas : el “Cuidador” ve una interfaz
“estrecha” que sólo le permite pasar el “Recuerdo” a otros objetos y el “Originador” ve una
interfaz “amplia” que le permite acceder a los datos necesarios y hacer todas las
manipulaciones necesarias para restaurar un estado almacenado.
________________________________________________________________________________
- 49 -
Colección de patrones Banda de los Cuatro

· Sólo el “Originador” puede meter y sacar información en el “Recuerdo”, que


resulta, por tanto, opaco (caja negra) para el resto de los objetos.
· Cuando los “Recuerdos” se crean y se retrotraen en un orden prefijado, entonces
se puede almacenar sólo el “cambio incremental” que cada uno hace sobre el estado del
anterior (ver Acción) y las operaciones con posibilidad de “deshacer/rehacer”.
· La misión del “Recuerdo” es simplemente la de ser un objeto que guarde una
“instantánea” del estado interno del objeto que lo invoca (el “Originador”), mientras que el
“Cuidador” es el responsable de la custodia segura del “Recuerdo”.

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();

sol -> Mover(-posición);


sol -> FijarRecuerdo(recuerdo);
SOLITARIO / SINGLETON 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.

Otros aspectos de interés


· El método “Instancia” es el punto de acceso a la “InstanciaÚnica” del “Solitario”
para los clientes. Lo que ocurre en realidad con este método es que, si “InstanciaÚnica”
no ha sido aún creada, la crea (INICIALIZACIÓN PEREZOSA) llamando al constructor
“Solitario”, que no es público.

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 :

FILTRO DIGITAL conversor CONVERSOR A/D

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

ELEMENTO A ELEMENTO B VISITANTE CONCRETO 1 VISITANTE CONCRETO 2

OperaciónA() OperaciónB() VisitarElementoA(ElementoA) VisitarElementoA(ElementoA)


Aceptar(Visitante v) Aceptar(Visitante v) VisitarElementoB(ElementoB) VisitarElementoB(ElementoB)

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

· Añadir un nuevo tipo de elemento a la estructura de objetos crea problemas, pues


hay que tocar toda la estructura jerárquica de “Visitantes”, lo cual es muy costoso.
· Frecuentemente se fuerza a los “Elementos” a proporcionar operaciones públicas
que den acceso a su estado interno, con lo que se pone en peligro el encapsulamiento.

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.

Otros aspectos de interés


· La técnica de programación que posibilita añadir operaciones a las clases de la
“Estructura De Objetos” sin cambiarlos, recibe el nombre de “double dispatch”, pues su
ejecución depende del tipo del peticionario y de los dos receptores : el “Visitante” y el
“Elemento”. Hay lenguajes (CLOS) que lo soportan directamente y otros (C++) que sólo
tienen “simple dispatch”, por lo que deben pasar el “Visitante” como parámetro.
· La responsabilidad de recorrer la “Estructura De Objetos” puede recaer en la
propia estructura (es frecuente), en un Iterador, que puede ser externo o interno (parecido
a la primera opción, salvo en que ahora no hay “double dispatch”) o en el “Visitante” (nos
permite implementar una política compleja particular para el recorrido, pero duplica el
código en cada “Visitante” concreto).
· La “Estructura De Objetos” puede ser una composición o una colección de objetos
(lista, conjunto, ... ) que proporciona una interfaz de alto nivel para que el “Visitante”
pueda acceder a todos sus “Elementos”.

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.

NODO COMPILADOR VISITANTE DE NODO

Aceptar(VisitanteDeNodo) VisitarAsignación(NodoAsignación)
VisitarVariable(NodoVariable)

PROGRAMA

NODO_ASIGNACIÓN NODO_VARIABLE VISITANTE_COMPR_TIPOS VISITANTE_GEN_CODIGO

Aceptar(Visitante v) Aceptar(Visitante v) VisitarAsignación(NodoAsignación) VisitarAsignación(NodoAsignación)


VisitarVariable(NodoVariable) VisitarVariable(NodoVariable)

v->VisitarAsignación(this); v->VisitarVariable(this);

________________________________________________________________________________
- 54 -

You might also like