Guía de Patrones de Diseño OO
Guía de Patrones de Diseño OO
Patrones de Diseño
Universo Santa Tecla
[email protected]
Version 0.0.1
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 1/117
19/1/2021 Patrones de Diseño
Índice
¿Por qué?
¿Cuándo? ¿Dónde? ¿Quién?
¿Qué?
¿Para qué?
¿Cómo?
Elementos
Elementos Esenciales
Problema
Solución
Consecuencias
Clasi cación
Patrones Creacionales
Abstract Factory
Builder
Factory Method
Prototype
Singleton
Patrones Estructurales
Adapter
Bridge
Composite
Decorator
Facade
Flyweight
Proxy
Patrones de Comportamiento
Chain of Responsibility
Command
Interpreter
Iterator
Mediator
Memento
Observer
State
Strategy
Template Method
Visitor
Relaciones
Aplicación
Bibliografía
Ponente
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 2/117
19/1/2021 Patrones de Diseño
¿Por qué?
Problemas de Diseño el diseño es difícil y reutilizable es incluso más difícil
Poner a funcionar los mecanismos de reutilización Reusabilidad por composición, herencia y/o
parametrización
Problemas de Rediseño el diseño debería ser específico para el problema actual pero
también en general para direccionar futuros problemas y
requisitos y, así, evitar rediseños o al menos minimizarlos
Los expertos, en diseño Obtener un diseño reusable y flexible correctamente a la primera es difícil, sino
orientados a objetos o cualquier no imposible
ámbito/disciplina/…,
No resolver cada problema desde cero
comparten/sugieren/…
Conocimiento/Know How: Intentar reusar una buena solución varias veces modificándola cada vez
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 3/117
19/1/2021 Patrones de Diseño
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 4/117
19/1/2021 Patrones de Diseño
¿Qué?
— Alexander
A Pattern Language
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 5/117
19/1/2021 Patrones de Diseño
¿Para qué?
Registrar la experiencia en diseño Producto Software
efectivamente.
reutilización.
rápido.
importantes y recurrentes en un
sistema orientado a objetos.
ProblemaRecurrente
Mejorar la documentación y
mantenimiento de los sistemas
existentes mediante el suministro Problema de Diseño Problema de Rediseño
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 6/117
19/1/2021 Patrones de Diseño
¿Cómo?
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 7/117
19/1/2021 Patrones de Diseño
Elementos
Elementos Esenciales
Para la descripción general del patrón se proponen 13
Patrón
elementos agrupados en 4 elementos esenciales:
Nombre
Patrón
Elemento de Patrón
Nombre Sinónimo
Nombre Una o dos palabras que transmiten la esencia del patrón (problema, solución y consecuencias) Singleton
permite:
Problema
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 8/117
19/1/2021 Patrones de Diseño
Patrón
Elemento de Patrón
Motivación Contexto para Para algunas clases es importante compartir una única instancia en el sistema.
entender el Ejemplos:
problema de
aunque haya muchas impresoras en un sistema, debería haber una única cola de
diseño abstracto
impresión
(representar
algoritmos como debería haber un solo sistema de ficheros y un solo gestor de ventanas
objetos, un filtro digital tendría un único convertidor analógico/digital
estructura
un sistema de cuentas bancarias será dedicado para servir a una compañía
inflexible de
clases u objetos, Código global, sin objeto!!! Código
…) y cómo (https://github.com/miw-
resolver el upm/IWVG/tree/master/doo/src/main/java/designPatterns/patterns/singleton/v1/basic/notObject)
problema
Intención Describe qué Asegurar que una clase tenga una única instancia y proveer un punto de acceso global para
razón de ser y ésta
qué hace el
patrón de
diseño sobre el
problema que
aborda
Aplicabilidad Lista de Debe ser exactamente una única instancia de la clase y debe ser accesible a los clientes
condiciones de desde un punto de acceso bien conocido.
ejemplos de
Cuando la única instancia debería ser extensible por sub-clasificación y los clientes
diseños pobres
deberían ser capaces de usar la instancia extendida sin modificar su código
que se deben
cumplir para
que tenga
sentido aplicar
el patrón
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 9/117
19/1/2021 Patrones de Diseño
Patrón
Estructura Participantes Colaboraciones Implementación Códgios de Ejemplo Usos Conocidos Patrones Relacionados
Estructura Diagrama de
Singleton
clases del patrón
Singleton instance
attribute
getInstance()
method()
Participantes Reparto de Singleton define una operación Instance que permite a los clientes acceder a su única
responsabilidades instancia.
entre las clases del
Instance es una operación de clase (miembro estático)
patrón
Singleton puede ser responsable de crear su propia instancia única
Colaboraciones Diagrama de Los clientes acceden a la instancia única a través de la operación Instance de Singleton
secuencia de los
objetos de las
clases del patrón
private attribute;
private Printer(){
// init
}
public method(){
// body
}
}
Consecuencias
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 10/117
19/1/2021 Patrones de Diseño
Patrón
Consecuencia Ventajas y desventajas, Acceso controlado a una única instancia. Como la clase encapsula su
compromisos de única instancia, puede tener un control estricto sobre cómo y cuándo
espacio/tiempo, cuestiones del los clientes acceden a ésta.
lenguaje (estático) y de
Reducir el espacio de nombres. Es una mejora sobre las variables
ejecución (dinámico).
globales ya que se evita contaminar el espacio de nombres con las
Impacto en la reutilización, variables globales que almacenen las instancias únicas.
flexibilidad, extensibilidad o
Permite el refinamiento de operaciones y su representación. Se
portabilidad de un sistema,
pueden tener subclases y es fácil configurar una aplicación con una
indicando qué parte
instancia de esta clase extendida que se necesite en tiempo de
permite variar de forma
ejecución.
independiente
Permite un número variable de instancias. Facilita cambiar de
Evaluación de alternativas
opinión y permitir más de una instancia de la clase. Además, se puede
de diseño con la
utilizar el mismo enfoque para controlar el número de instancias que
comprensión de los costes y
utiliza la aplicación.
beneficios de aplicar el
patrón. Más flexible que operaciones de clase (static). Esta técnica hace que
sea difícil cambiar un diseño para permitir más de una instancia de
una clase. Y las subclases no pueden redefinirlas polimórficamente
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 11/117
19/1/2021 Patrones de Diseño
Clasificación
Patrón
Elemento de Patrón Nombre Patron Creacional Patrón Estructural Patrón de Comportamiento Propósito
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 12/117
19/1/2021 Patrones de Diseño
Patrones Creacionales
Patrón
ProductoConcretoA ProductoConcretoB
Abstract Factory
Problema
Motivación
Código de Contraejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/AbstractFactory/abstractFactoryWrong)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 13/117
19/1/2021 Patrones de Diseño
Intención
Si la responsabilidad
Scenario
de cirujano incluye
únicamente la main()
solicitud de
instrumental
abstracto (algo public operate(instrumentalist) {
...
cortante, algo secante,
«Director» instrumentalis.createCuttingTool();
…) y otros, Surgeon cutting Tool.cut();
instrumentalis.createDryingTool();
instrumentalistas, se operate(Instrumentalist) dryingTool.dry();
responsabilizan por ...
}
separado de cómo se
obtienen los
instrumentos
dependiendo de la «Abstract Factory»
Instrumentalist
localización, ninguna
createCuttingTool()
clase será compleja y createDryingTool()
se evitará la tendencia
a crecer.
«ConcreteFactoryA» «ConcreteFactoryB»
InstrumentalistinOperatingRoom «AbstractProductA» «AbstractProductB» InstrumentalistinJungle
CuttingTool DryingTool
createCuttingTool() createCuttingTool()
createDryingTool() createDryingTool()
Código de Ejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/AbstractFactory/abstractFactoryFine)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 14/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Un sistema debe ser independiente de cómo se crean, componen y representan
proporcionar una interfaz para sus productos.
crear familias de objetos
Un sistema debe ser configurado con una familia de productos de entre varias.
relacionados o dependientes
Una familia de objetos producto relacionados está diseñada para ser usada
entre sí sin tener que especificar
conjuntamente, y es necesario hacer cumplir esta restricción.
su clase concreta
Se quiere proporcionar una biblioteca de clases de productos, y sólo se desea
revelar sus interfaces, no sus implementaciones.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 15/117
19/1/2021 Patrones de Diseño
Scenario
AbstractFactory: declara una
clase abstracta o interfaz que
main()
define los métodos de creación
de los distintos tipos de
AbstractProduct.
public doSomething() {
Director
... Tiene una operación que
abstractFactory.createProductA();
... devuelve un nuevo objeto
doSomething(abstractFactory) abstractFactory.createProductB();
} para cada clase abstracta de
producto. Los tipos de
producto está codificados en
las signaturas de las
Abstract Factory
operaciones. Añadir un nuevo
tipo de producto requiere
createProductA()
createProductB()
cambiar la interfaz de
AbstractFactory y todas las
clases que dependen de ella.
ConcreteFactoryA ConcreteFactoryB
AbstractProductA AbstractProductB
createProductA() createProductA()
Los clientes llaman a estas
createProductB() createProductB()
operaciones para obtener
instancias de productos, pero
no son conscientes de las
ConcreteProductAA ConcreteProductBA ConcreteProductAB ConcreteProductBB clases concretas que están
usando. En otras palabras, los
clientes no tienen que atarse
a una clase concreta, sino sólo
a una interfaz definida por
una clase abstracta.
AbstractProduct: declara una clase abstracta o interfaz para un tipo de objeto producto.
ConcreteFactory: clase derivada de AbstractFactory que implementa los métodos para crear objetos producto concretos.
El modo más común de hacer esto es definiendo un método de fabricación para cada producto.
ConcreteProduct: clase derivada del AbstractProduct que representa un producto concreto para un estándar concreto de
interfaz de usuario.
Implementación
Variaciones
Un diseño más flexible, aunque menos seguro, es añadir un parámetro a las operaciones que crean los objetos. Este
parámetro especifica el tipo de objeto a ser creado. Podría tratarse de un identificador de clase, un entero, una cadena de texto
o cualquier otra cosa que identifique el tipo de producto. De hecho, con este enfoque, AbstractFactory solo necesita una única
operación create con un parámetro que indique el tipo de objeto a crear.
Podemos aplicarla en Java, C++, etc. sólo cuando todos los objetos tienen la misma clase abstracta o cuando los objetos
producto pueden ser convertidos con seguridad al tipo concreto por el objeto que lo solicita. Pero incluso cuando no es
necesaria la conversión de tipos, todavía subyace un problema inherente: todos los productos se devuelven al cliente con la
misma interfaz abstracta que el tipo de retorno. El cliente no podrá por tanto distinguir o hacer suposiciones seguras acerca
de la clase de un producto. En caso de que los clientes necesiten realizar operaciones específicas de las subclases,
éstas no estarán accesibles a través de la interfaz abstracta. Aunque el cliente podría hacer una conversión al tipo de
una clase hija, eso no siempre resulta viable o seguro, porque la conversión de tipo puede fallar. Éste es el inconveniente
típico de una interfaz altamente flexible y extensible.
Consecuencias
Ventajas Desventajas
El patrón Abstract Factory ayuda a controlar las clases de objetos que crea una Ampliar la AbstractFactory para
aplicación. Como una AbstractFactory encapsula la responsabilidad y el proceso de producir nuevos tipos de
creación de objetos producto, aísla a los clientes de las clases de implementación. productos no es fácil. Esto se
Los clientes manipulan las instancias a través de sus interfaces abstractas. Los debe a que la interfaz
nombres de las clases producto quedan aisladas en la implementación de la AbstractFactory fija el conjunto
ConcreteFactory; no aparecen en el código cliente. de productos que se pueden
crear.
La clase ConcreteFactory sólo aparece una vez en una aplicación, cuando se crea.
Esto facilita cambiar la ConcreteFactory que usa una aplicación. Como una Permitir nuevos tipos de
AbstractFactory crea una familia completa de productos, toda la familia de productos requiere ampliar la
productos cambia de una vez. interfaz, lo que a su vez
implica cambiar la clase
Cuando se diseñan objetos producto en una familia para trabajar juntos, es
AbstractFactory y todas sus
importante que una aplicación use objetos de una sola familia a la vez. El patrón
subclases.
Abstract Factory facilita que se cumpla esta restricción.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 16/117
19/1/2021 Patrones de Diseño
Determinar la granularidad de los objetos Granularidad Crear un objeto especificando su clase Acoplamiento
explícitamente
Builder
Problema
Motivación
Una persona se
Scenario
responsabiliza de
una dieta variada main()
de menús, básico o
gourmet o …, todos
ellos compuestos
por diferentes public eat() {
platos: entrante, if(dish == Dish.BASIC) {
...
ensalada u ostras o this.prepareSalad();
Person
…; plato principal, this.prepareChicken();
pollo o solomillo o this.prepareCustard();
eat()
...
…; postre, natillas o prepareSalad()
} else if (dish == Dish.Gourmet) {
prepareChiken()
soufflé o … prepareCustard() ...
prepareOyster() this.prepareOyster();
prepareSirloin() this.prepareSirloin();
prepareSouffle() this.prepareSouffle();
...
}
}
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 17/117
19/1/2021 Patrones de Diseño
Intención
Si la Scenario
responsabilidad main()
de la persona
incluye
public eat(Chef) {
únicamente la «Director»
...
chef.prepareStarter();
solicitud del Person
chef.prepareMainCourse();
chef.prepareDessert();
eat(Chef)
menú (básico, }
...
gourmet, …) y otros,
cocineros, se
responsabilizan «AbstractBuilder»
Chef
prepareStarter() prepareStarter()
tipo de menú, prepareMainCourse() prepareMainCourse()
prepareDessert() prepareDessert()
ninguna clase será
compleja y se
evitará la tendencia «AbstractProduct»
Dish
a crecer.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 18/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es El algoritmo para la creación de un objeto complejo debe ser independiente de
separar la construcción de un las partes que componen el objeto y la forma en que están montadas.
objeto complejo de su
El proceso de construcción debe permitir diferentes representaciones para el
representación, de tal forma
objeto que se construye.
que el mismo proceso de
construcción puede crear
diferentes representaciones.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 19/117
19/1/2021 Patrones de Diseño
ConcreteBuilderA ConcreteBuilderB
AbstractProduct
buildPart() buildPart()
getResult() getResult()
ConcreteProductA ConcreteProductB
ConcreteBuilder: clase derivada de AbstractBuilder que redefine las operaciones de construcción de las piezas en las que
está interesado para la creación del producto final. Se encarga también de ensamblar dichas piezas para componer el
ConcreteProduct y devolver una instancia de este.
A veces, podríamos necesitar acceder a las partes del producto que ya fueron construidas. Con las estructuras arbóreas
que se crean de abajo a arriba, el ConcreteBuilder devolvería nodos hijos al Director, el cual los devolvería al constructor
para construir los nodos padre.
AbstractProduct: declara una clase abstracta o interfaz para un tipo de objeto producto.
En general, los ConcreteProduct creados por los ConcreteBuilder tienen representaciones tan diferentes que suele ser de
poca utilidad definir una clase padre común AbstractProduct para los diferentes productos.
Normalmente, como el cliente suele configurar al Director con el ConcreteBuilder adecuado, sabe qué subclase concreta
de Builder se está usando y puede manejar sus productos en consecuencia.
Implementación
Variaciones
En general, los ConcreteProduct creados por los ConcreteBuilder tienen representaciones tan diferentes que suele ser de poca
utilidad definir una clase padre común AbstractProduct para los diferentes productos.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 20/117
19/1/2021 Patrones de Diseño
Factory Method
Problema
Motivación
Un repartidor se
Scenario
responsabiliza
del reparto de
main()
paquetes con el
mismo algoritmo,
recoger paquete,
localización del
public deliver() {
destino, seleccionar
...
vehículo disponible, if (vehicle == AvailableVehicle.BYCYCLE) {
conducir, entregar this.getBicycle();
paquete, … pero } else if (vehicle == AvailableVehicle.MOTORCYCLE) {
dependiendo de this.getMotocycle();
DeliveryMan }
los tipos de
...
vehículo }
deliver()
disponibles, lo getBicycle()
realizará con un getMotocycle() public getBicycle {
return new Bicycle();
vehículo u otro,
}
bicicleta o moto o …
public getMotorcycle() {
return new Motorcycle();
}
«AbstractProduct»
Vehicle
«ConcreteProductA» «ConcreteProductB»
Bicycle Motorcycle
Código de Contraejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/FactoryMethod/factoryMethodWrong)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 21/117
19/1/2021 Patrones de Diseño
Intención
Si la Scenario
responsabilidad
main()
de repartidor
incluye
únicamente la public deliver() { «Creator»
...
solicitud de un this.getVehicle();
DeliveryMan
vehículo }
... getVehicle()
deliver()
abstracto y otros,
repartidores
concretos, se «ConcreteCreatorA» «ConcreteCreatorB»
public getVehicle() «AbstractProduct» public getVehicle() {
CyclistDeliveryMan MotorcyclistDeliveryMan
responsabilizan return new Bicycle(); Vehicle return new Motorcycle();
} }
por separado de
getVehicle() getVehicle()
cómo se obtiene el
vehículo concreto
«ConcreteProductA» «ConcreteProductB»
dependiendo de Bicycle Motorcycle
los vehículos
disponibles,
ninguna clase será
compleja y se
evitará la tendencia
a crecer.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 22/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Una clase no puede prever la clase de objetos que debe crear.
definir una interfaz para
Una clase quiere que sean sus subclases quienes especifiquen los objetos que
crear un objeto, pero delegar
ésta crea.
a las subclases qué clase
concreta instanciar, Las clases delegan la responsabilidad en una de entre varias clases auxiliares y
permitiendo a una clase queremos localizar qué subclase de auxiliar concreta es en la que se delega.
diferir la instanciación a las
subclases.
Solución
public doSomething() {
(Factory Method) de los distintos
Creator
...
this.factoryMethod();
tipos de ConcreteProduct.
... factoryMethod()
doSomething()
}
Podría tratarse también de
una clase concreta que
public getConcreteProductA() { ConcreteCreatorA ConcreteCreatorB public getConcreteProductB() { proporcione una
AbstractProduct
return new ConcreteProductA(); return new ConcreteProductB();
} factoryMethod() factoryMethod() } implementación
predeterminada del método
de fabricación.
ConcreteProductA ConcreteProductB
AbstractProduct: declara una clase abstracta o interfaz para un tipo de objeto producto.
ConcreteCreator: clase derivada de Creator que implementa el método de fabricación (Factory Method) para crear su
correspondiente ConcreteProduct.
ConcreteProduct: clase derivada del AbstractProduct que representa un producto concreto para un estándar concreto de
interfaz de usuario.
Implementación
Variaciones
Las dos principales variantes del patrón Factory Method son:
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 23/117
19/1/2021 Patrones de Diseño
La clase Creator es una clase abstracta y no proporciona una implementación para el método de fabricación que
declara. Requiere que las subclases definan una implementación porque no hay ningún comportamiento predeterminado
razonable.
La clase Creator es una clase abstracta (menos común) o concreta y proporciona una implementación predeterminada
del método de fabricación. El ConcreteCreator usa el método de fabricación principalmente por flexibilidad. Lo hace
siguiendo una regla que dice: “crear objetos en una operación aparte, para que las subclases puedan redefinir el modo en
que son creados”. Esta regla asegura que los diseñadores de las subclases puedan cambiar la clase de objetos.
Otra variante del patrón permite que los métodos de fabricación creen varios tipos de productos. El método de
fabricación recibe un parámetro que identifica el tipo de objeto a crear. Todos los objetos creados por el método compartirán
la interfaz AbstractProduct.
Un potencial problema de los métodos de fabricación es que pueden obligar a usar la herencia sólo para crear los objetos
ConcreteProduct apropiados. Otra forma de hacer esto es proporcionar una subclase genérica de Creator
parametrizada con la clase de ConcreteProduct.
Consecuencias
Ventajas Desventajas
Los clientes pueden encontrar útiles los métodos de Un inconveniente potencial de los métodos de fabricación
fabricación, especialmente en el caso de jerarquías de es que los clientes pueden tener que crea subclases de
clases paralelas. Creator sólo para fabricar un nuevo tipo de
ConcreteProduct. La herencia está bien siempre y
Las jerarquías de clases paralelas se producen cuando
cuando el cliente tenga que crear las subclases de
una clase delega alguna de sus responsabilidades a una
todos modos, ya que, si no, se estaría introduciendo
clase separada (como las clases de estructuras de datos
una nueva vía de futuros cambios.
y la obtención de sus iteradores). Los métodos de
fabricación definen la conexión entre las dos jerarquías
de clases, localizando qué clases van juntas.
Prototype
Problema
Motivación
En un parque, un
Scenario
poeta se
responsabiliza de
main()
vender poemas
famosos que
escribe en el
momento en que se
public sell(poemid) {
lo piden porque se
if (poemid == "La Casada Infiel") { Poet
los sabe de return this.createLaCasadaInfiel();
memoria. Pero si } else if (poemid == "PoemaXX") { sell(poemid)
cambian los gustos, return this.createPoemaXX(); createLaCasadaInfiel()
tendrá que } createPoemaXX()
}
adaptarse y
aprender nuevos
poemas.
Poem
LaCasadaInfiel PoemaXX
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 24/117
19/1/2021 Patrones de Diseño
Intención
Si la
Scenario
responsabilidad
de poeta incluye
main()
únicamente la
solicitud de una
copia del poema
solicitado y otros,
public sell(poem, poemid) {
poemas
... «Director»
concretos, se requestedPoem = poem.getPoem(poemid) Poet
responsabilizan requestedPoem.copy();
por separado de ... sell(poemid)
cómo se obtiene la }
copia del poema,
ninguna clase será
compleja y se
evitará la tendencia «Prototype»
a crecer. Poem
getPoem()
copy()
«ConcretePrototypeA» «ConcretePrototypeB»
LaCasadaInfiel PoemaXX
copy() copy()
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 25/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Un sistema deba ser independiente de cómo se crean, se componen y se
especificar las clases de representan sus productos y se cumpla alguna de las siguientes condiciones:
objetos a crear usando una
Las clases a instanciar sean especificadas en tiempo de ejecución (por ejemplo,
instancia prototípica y crear
mediante carga dinámica).
nuevos objetos por copias de
este prototipo. Se quiera evitar construir una jerarquía de clases fábrica paralela a la
jerarquía de clases de los productos.
Las instancias de una clase puedan tener uno de entre sólo unos pocos estados
diferentes. En esta situación puede ser más adecuado tener un número
equivalente de prototipos y clonarlos, en vez de crear manualmente instancias de
la clase cada vez con el estado apropiado.
Solución
Scenario
Prototype: declara una clase
abstracta o interfaz para
main()
clonarse.
Prototype
clone()
ConcretePrototypeA ConcretePrototypeB
clone() clone()
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 26/117
19/1/2021 Patrones de Diseño
ConcretePrototype: clase derivada de Prototype que implementa el método de clonación. El método de clonación devuelve
una instancia de la misma clase con los mismos valores que la instancia Prototype original. La nueva instancia puede ser
una copia profunda o superficial del original.
Director: clase que solicita la creación de un objeto utilizando la interfaz de clonación proporcionada por Prototype.
Implementación
Variaciones
«ConcretePrototypeB» «ConcretePrototypeA»
PoemaXX LaCasadaInfiel
copy() copy()
Código ejemplo
(https://github.com/USantaTecla-
disenyo/designPatterns/tree/master/src/main/java/usantatecla/Prototype/prototypeFineWithRegistry)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 27/117
19/1/2021 Patrones de Diseño
En cuanto al método de clonación, que es la parte más complicada de implementar del patrón Prototype (especialmente
cuando las estructuras de objetos contienen referencias circulares), existen dos variantes, copia superficial y copia profunda:
Copia superficial: sólo duplica los elementos de alto nivel de una clase; esto proporciona una copia más rápida, pero no
siempre resulta apropiada (los objetos de bajo nivel son compartidos entre las copias del objeto, por lo que cualquier
cambio en ellos afectaría a todas las copias).
Copia profunda: duplica tanto los atributos de alto nivel como los objetos de bajo nivel. Esto suele llevar más tiempo y
puede ser costoso para objetos con una estructura compleja, pero asegura que los cambios en una copia se aíslan de las
otras copias. Mediante la copia profunda se garantiza que el clon y el original son independientes, es decir, que los
componentes del clon son clones de los componentes del prototipo.
La mayoría de los lenguajes proporcionan algún tipo de ayuda para clonar objetos (clone(), constructor de copia, …). Pero
estas facilidades no resuelven el problema de la copia superficial frente a la copia profunda. La clonación nos obliga a
decidir qué será compartido, si es que lo será algo.
Mientras que a algunos clientes les sirve el clon tal cual, otros necesitarán inicializar parte de su estado interno, o todo, con
valores de su elección. Generalmente no se pasan dichos valores en la operación clonar ya que esto impediría tener una
interfaz de clonación uniforme, puesto que el número de valores a inicializar variará de unas clases de prototipos a otras
(algunos prototipos pueden necesitar múltiples parámetros de inicialización; otros no necesitarán ninguno).
Puede darse el caso de que nuestras clases prototipo ya definan operaciones para establecer las partes principales de su
estado. Si es así, los clientes pueden usar estas operaciones inmediatamente después de la clonación.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 28/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
Oculta al cliente las clases producto concretas, reduciendo así el número de nombres que conocen los
clientes. Además, permite que un cliente use las clases específicas de la aplicación sin cambios.
Permite incorporar a un sistema una nueva clase concreta de producto simplemente registrando
una instancia prototípica con el cliente. Esto es algo más flexible que otros patrones de creación, ya que
un cliente puede instalar y eliminar prototipos en tiempo de ejecución.
Este tipo de diseño permite que los usuarios definan nuevas “clases” sin programación. De hecho, clonar
un prototipo es parecido a crear una instancia de una clase. El patrón prototipo puede reducir en gran
medida el número de clases necesarias en un sistema.
El patrón Prototype permite reducir la herencia. Los patrones Abstract Factory y Factory Method suele
producir una jerarquía de clases AbstractFactory y Creator que es paralela a la jerarquía de clases de
productos. El patrón Prototype permite clonar un prototipo en vez de decirle a un método de fabricación
que cree un nuevo objeto. Por tanto, no es en absoluto necesaria una jerarquía de clases AbstractFactory o
Creator. Este beneficio es aplicable principalmente a lenguajes como Java, C++, etc. que no tratan a las
clases como objetos en toda regla.
Singleton
Problema
Motivación
SecurityGuard
openSchool()
openClassRoom()
closeClassRoom()
provideSchoolKeys()
Esto tiende a crecer a medida que surgen nuevas clases organizativas a las que
será necesario presentar al guardia de seguridad aunque no requieran sus
servicios.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 29/117
19/1/2021 Patrones de Diseño
El acoplamiento de las clases organizativas La cohesión de las La granularidad de las clases organizativas
(School, ManagementBoard y Department) clases (School, ManagementBoard y Department)
varía para cada tipo de clase organizativa. En organizativas depende de la cantidad de parámetros
el caso de la clase School, depende del (School, requeridos en su constructor y del
número de entidades y del guardia de ManagementBoard parámetro correspondiente al guardia de
seguridad; y en el caso de las entidades y Department) no es seguridad. Dicha cantidad varía para cada
ManagementBoard y Department, depende adecuada puesto tipo de participante (ej. School, 0 + 1 = 1;
del tipo del profesor y del guardia de que asume varias ManagementBoard, 0 + 1 = 1; Department, 0 +
seguridad. responsabilidades 1 = 1), por lo que se considerará para el
dispares o que no análisis la media de todos los parámetros
Al tratarse de una cantidad que varía para
le atañen, como el de los constructores de las clases que
cada tipo de clase organizativa (ej. School, 3;
conocimiento del representan a los distintos tipos de clase
ManagementBoard, 2; Department, 2), se
guardia de organizativa (ej. 1).
considerará para el análisis la media de los
seguridad para que
acoplamientos de las clases que Se calcula como la media de los parámetros
éste pueda ser
representan a los distintos tipos de clases de los constructores de las clases que
presentado a los
organizativas (ej. 2,3). representan a los distintos tipos de clase
profesores.
organizativa más el parámetro del
Su resultado es de orden lineal, O(n).
guardia de seguridad; es decir, la suma de
los parámetros de los constructores de todas
las clases que representan un tipo de clase
organizativa (ej. 1 + 1 + 1 = 3) dividido entre el
número de tipos de clases organizativas (ej.
3).
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 30/117
19/1/2021 Patrones de Diseño
El uso de un
Scenario
servicio de guardia
de seguridad
main()
global permite la
flexibilidad de
localizar e
incluso cambiar
«Director»
de guardia sin
School
afectar a nadie.
School()
startAcademicYear()
ManagementBoard Departament
ManagementBoard() Departament()
«Singleton»
public getInstance() { SecurityGuard
if (securityGuard == null) { Printer printer
securityGuard = new SecurityGuard();
getInstance()
}
openSchool()
return securityGuard; openClassRoom()
} closeClassRoom()
provideSchoolKeys()
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 31/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Se requiere exactamente una única instancia de una clase y debe ser accesible a los
asegurar que una clase tenga clientes desde un punto de acceso bien conocido.
una sola instancia y proveer
Se precisa que la única instancia sea extensible por subclasificación de tal manera
un punto de acceso global
que los clientes puedan ser capaces de usar la instancia extendida sin modificar su
para ésta.
código,
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 32/117
19/1/2021 Patrones de Diseño
Director
Implementación
Variaciones
ManagementBoard() Departament()
La utilización de un registro de objetos Singleton. En lugar de definir el conjunto
de posibles clases Singleton en getInstance, las clases Singleton pueden registrar su
única instancia por su nombre en un registro conocido (por ejemplo, en su public Professor(
this.title = title;
constructor). Código de ejemplo }
this.securityGua
Professor
(https://github.com/miw-
public teach() {
upm/IWVG/tree/master/doo/src/main/java/designPatterns/patterns/singleton/v6/subclassifing/cpp) Professor(String}
teach()
this.securityGua
// teaching
...
this.securityGua
}
PublicSecurityGuard PrivateSecurityGuard
openSchool() openSchool()
openClassRoom() openClassRoom()
closeClassRoom() closeClassRoom()
provideSchoolKeys() provideSchoolKeys()
Cógigo de ejemplo
(https://github.com/USantaTecla-
disenyo/designPatterns/tree/master/src/main/java/usantatecla/Singlet
Consecuencias
Ventajas Desventajas
Permite tener un control estricto sobre cómo y cuándo los clientes acceden a la
instancia única de la clase.
Supone una mejora sobre el uso de variables globales ya que evita contaminar el
espacio de nombres con variables globales que almacenen las instancias.
Permite tener subclases y es fácil configurar una aplicación con una instancia de
una clase extendida que se necesite en tiempo de ejecución.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 33/117
19/1/2021 Patrones de Diseño
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 34/117
19/1/2021 Patrones de Diseño
Patrones Estructurales
Patrón
se ocupan de cómo se combinan las se basan en un mismo pequeño tienen estruturas de clases muy
clases y los objetos para formar conjunto de mecaninsmos del similares que ocultan los
estructuras más grandes. lenguaje para estructurar el código: diferentes propósitos de estos
herencia de clases simple y patrones.
múltiple y composición de objetos
Adapter
Problema
Motivación
Cuando se viaja al extranjero, existen problemas al enchufar los aparatos eléctricos (secador de pelo, maquinilla de afeitar,
…) porque el número, forma y/o disposición de las patillas de los enchufes no son iguales en todos los países, ya que existen
distintos estándares.
Un solución costosa y engorrosa sería comprar nada más llegar al destino todos los aparatos eléctricos con el
estándar del país de destino y guardarlos en el trastero hasta que se vuelva a viajar a un país del mismo estándar.
main()
comprensión de
su comportamiento
y tiende a crecer a
ShaverC HairdryerC
PowerplugC PowerPlugF
ShaverF HairdryerF medida que
plug(PowerPointC) plug(PowerPoitF) surgen nuevos
países de destino
PowerPointC PowerPointF
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 35/117
19/1/2021 Patrones de Diseño
Intención
aparatos
eléctricos del
origen y «Adapter»
únicamente HairdryerC ShaverC PowerPointF AdapterPawerPlugF
comprar plug(PawerPointC)
adaptadores
antes de viajar a
un destino de otro «Adaptee»
estándar y PawerPlugC
para el próximo
viaje a un país con
el mismo estándar.
PowerPointC
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 36/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Se quiere crear una clase reutilizable que coopere con clases no relacionadas o que
convertir la interfaz de una no han sido previstas, es decir, clases que no tienen por qué tener interfaces
clase en otra interfaz que el compatibles.
cliente espera, permitiendo
Se quiere usar una clase existente (ej. una clase de una biblioteca que ha sido
trabajar clases conjuntamente
diseñada para reutilizarse) y su interfaz no concuerda con la que se
que no podrían de otra
necesita (específica del dominio que requiere la aplicación).
manera por la
incompatibilidad de sus
interfaces.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 37/117
19/1/2021 Patrones de Diseño
Scenario Scenario
main() main()
Adaptee
spesificRequest()
Target: declara una interfaz específica del dominio que usa el cliente.
Scenario: colabora con objetos que se ajustan a la interfaz Target, y utiliza el Adapter para poder colaborar con objetos que
se ajusten a la interfaz Adaptee.
Implementación
Variaciones
Adapter de clases: adapta una clase Adaptee a Target, pero se refiere únicamente a una clase Adaptee concreta. Por tanto, un
Adapter de clases no nos servirá cuando lo que queremos es adaptar una clase y todas sus subclases.
En una implementación en C++ de un Adapter de clases, el Adapter debería heredar públicamente de Target y privadamente
de Adaptee. Así, Adapter sería un subtipo de Target , pero no de Adaptee.
Se precisa definir las correspondientes operaciones abstractas para la interfaz reducida de Adaptee.
Adapter de objetos: permite adaptar varias subclases Adaptee existentes, es decir, el Adaptee- en sí y todas sus subclases en
caso de que las tenga. En esta situación no resulta práctico adaptar su interfaz heredando de cada una de ellas. Un Adapter de
objetos puede adaptar la interfaz de su clase padre.
El cliente reenvía las peticiones para acceder a la estructura jerárquica a un objeto delegado.
El cliente puede usar una estrategia de adaptación diferente cambiando el objeto delegado.
Consecuencias
Ventajas Desventajas
Adapter de objetos: Permite que un mismo Adapter funcione con muchos Adaptee,
es decir, con el Adaptee en sí y todas sus subclases, en caso de que las tenga. El
Adapter puede añadir funcionalidad a todos los Adaptee a la vez.
Una clase es más reutilizable cuando minimizamos las asunciones que deben hacer
otras clases para usarla. Al hacer la adaptación de interfaces en una clase estamos
eliminando la asunción de que otras clases ven la misma interfaz. Dicho de otro
modo, la adaptación de interfaces nos permite incorporar nuestra clase a
sistemas existentes que podrían esperar interfaces diferentes a la de la clase.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 38/117
19/1/2021 Patrones de Diseño
Bridge
Problema
Motivación
Un asesor se Scenario
responsabiliza de main()
asesorar mediante
informes que
Adviser
presentan
advise()
adecuadamente
análisis de grandes
volúmenes de datos CasualAdviser FormalAdviser
de detalle,
superficial o formal
CasualFinancialAdviser CasualTaxAdviser CasualLegalAdviser FormalFinancialAdviser FormalTaxAdviser FormalLegalAdviser
o …, sobre
advise() advise() advise() advise() adviser() advise()
distintas áreas,
económica o fiscal o
legal o … EconomyMinistry TaxMinistry LawMinistry
Además, la
cohesión se ve
también
perjudicada por la
falta de
centralización de
las distintas áreas,
que se encuentran
replicadas en la
jerarquía de
herencias paralela
existente en los
analistas.
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 39/117
19/1/2021 Patrones de Diseño
Si la Scenario
responsabilidad main()
de asesor incluye
únicamente la
«Abstraction» «Implementation»
la información
advise() analyze()
analistas, se
responsabilizan
por separado de
EconomyMinistry TaxMinistry LawMinistry
cómo se obtiene la
información para
las distintas
áreas, ninguna
clase será compleja
y se evitará la
tendencia a crecer.
Intención Aplicabilidad
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 40/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Evitar una relación estática entre una abstracción y su implementación. Por
desacoplar una abstracción de ejemplo, cuando debe seleccionarse o cambiarse la implementación en tiempo de
su implementación de tal ejecución.
forma que las dos pueden
Permitir que tanto las abstracciones como sus implementaciones sean
variar independientemente.
extensibles mediante subclasificación. En este caso, el patrón Bridge permite
multiplexar las opciones para las diferentes abstracciones y sus implementaciones, y
extenderlas independientemente.
Solución
Scenario
Abstraction: declara la interfaz
de la abstracción, pudiendo
main()
proporcionar un
comportamiento y una
public operation() { Abstraction Implementor
estructura estándar. Además,
impl.operationImpl();
contiene una referencia a un
} operation() operationImpl()
objeto de tipo Implementor, que
normalmente se fija por medio
de un método set o a través del
ConcreteImplementorA ConcreteImplementorB
RedefinedAbstractionB RedefinedAbstractionA
constructor.
operationImpl() operationImpl()
RefinedAbstraction: clase
derivada de Abstraction que
extiende su interfaz
proporcionando un
comportamiento adicional o
modificado.
Esta interfaz no tiene por qué corresponderse exactamente con la de la abstracción. De hecho, suelen ser muy distintas,
proporcionando la interfaz Implementor operaciones abstractas primitivas que la interfaz Abstraction utiliza para
ofrecer operaciones de más alto nivel.
Es decir, todas las operaciones de las subclases de la abstracción se implementan en términos de operaciones abstractas
de la interfaz del implementador. Esto desacopla las abstracciones de las diferentes implementaciones específicas de
cada plataforma. Nos referimos a la relación entre la abstracción y la implementación como un puente, porque una
abstracción con su implementación, permitiendo que ambas varíen de forma independiente.
Implementación
Variaciones
En situaciones en las que sólo hay una implementación no es necesario crear una clase abstracta Implementor. Éste es
un caso degenerado del patrón Bridge, cuando hay una relación uno-a-uno entre Abstraction e Implementor. Sin embargo, esta
separación sigue siendo útil cuando un cambio en la implementación de una clase no debe afectar a sus clientes existentes, es
decir, éstos no deberían ser recompilados, sólo enlazados.
Si Abstraction conoce a todas las clases ConcreteImplementor, puede crear una instancia de una de ellas en su
constructor; puede decidir de cuál basándose en los parámetros recibidos en él.
Otro enfoque consiste en elegir inicialmente una implementación predeterminada y cambiarla después en función de su
uso.
También es posible delegar totalmente la decisión en otro objeto. Por ejemplo, Abstract Factory sabe qué tipo de
objetos ConcreteImplementor crear para la plataforma en uso. Una ventaja es que Abstraction no está acoplada
directamente a ninguna de las clases Implementor.
Algunas clases de implementación, especialmente las clases sin estado (que no mantienen un estado interno), pueden ser
compartidas entre múltiples objetos de la aplicación.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 41/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
Composite
Problema
Motivación
En muchos juegos
Scenario
de mesa (trivial
pursuit, parchis, …)
main()
hay limitaciones en
el tablero para el
número máximo
de jugadores y,
cuando hay más Game
Person
play()
Código de Contraejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/Composite/compositeWrong)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 42/117
19/1/2021 Patrones de Diseño
Sí importa el orden.
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 43/117
19/1/2021 Patrones de Diseño
La solución más
Scenario
habitual es
nombrar un
main()
representante del
equipo y, de cara
al resto de
jugadores, se
«Director»
comporta como
Game
un único jugador.
Internamente el play(person1, person2)
play(person1, team1)
representante se play(team1,person1)
organizará play(team1, team2)
transparentemente
con el resto de
personas del equipo
para tomar «Component»
decisiones. Player
play()
«Composite»
public play() { Team
for each person in team {
person.play(); play()
} addPerson()
} removePerson()
getTeamMembers()
«Leaf»
Person
play()
Intención Aplicabilidad
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 44/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
Solución
Component
operation()
Opcionalmente:
Define una interfaz para acceder al padre de un componente en la estructura recursiva y, si es necesario, la implementa.
Leaf: clase derivada de Component que define el comportamiento de los objetos primitivos de la composición. Las
clases Leaf no tienen hijos.
Composite: clase derivada de Component que define el comportamiento de los objetos que tienen hijos. Por lo tanto,
almacena los componentes hijos e implementa las operaciones relacionadas con ellos.
Muchos diseños especifican una ordenación de los hijos de Composite. Cuando la ordenación de los hijos es una cuestión a
tener en cuenta, se deben diseñar las interfaces de acceso y gestión de hijos cuidadosamente para controlar la secuencia.
Director: clase que manipula los objetos de la composición a través de la interfaz Component.
Implementación
Variaciones
La clase Composite siempre es responsable de implementar las operaciones añadir y eliminar para controlar sus hijos, pero
existen dos alternativas para definir la interfaz de gestión de los hijos. La decisión implica un equilibrio entre seguridad
y transparencia:
Definir la gestión de los hijos en la clase Composite nos proporciona seguridad, ya que cualquier intento de añadir o
eliminar objetos de las hojas será detectado en tiempo de compilación en un lenguaje estáticamente tipado. Pero perdemos
transparencia porque las hojas y los compuestos tienen interfaces diferentes.
Definir la interfaz de gestión de los hijos en la raíz de la jerarquía de clases, Component, nos da transparencia, puesto
que podemos tratar a todos los componentes de manera uniforme. Sin embargo, sacrifica la seguridad, ya que los clientes
pueden intentar hacer cosas sin sentido, como añadir y eliminar objetos de las hojas.
Esta implementación a veces entra en conflicto con el principio de diseño de jerarquías de clases que dice que una
clase debería definir operaciones que tienen sentido en sus subclases, ya que hay muchas operaciones permitidas por
Component que no parecen tener sentido en las clases Leaf.
Se debe tener en cuenta también que definir el conjunto de hijos como una variable de instancia de la clase
Component, en la que se declaren las operaciones de acceso y gestión de hijos, supone una penalización de espacio para
los objetos de la clase Leaf, ya que se está almacenando un puntero que nunca será utilizado por éstos puesto que las
hojas nunca tendrán hijos. Por lo tanto, esto sólo merece la pena si hay relativamente pocos hijos en la estructura
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 45/117
19/1/2021 Patrones de Diseño
A veces un poco de creatividad muestra cómo una operación que podría parecer que sólo tiene sentido en el caso
de los Composite puede implementarse para todos los Component, moviéndola a la clase Component. Por ejemplo, la
interfaz para acceder a los hijos es una parte fundamental de la clase Composite, pero no de la clase Leaf. Pero si vemos
a una clase Leaf como un Component para acceder a los hijos que nunca devuelve ningún hijo, las clases Leaf pueden
usar esa implementación predeterminada, y las clases Composite pueden redefinir la implementación para devolver sus
hijos.
Scenario
main()
Director
Component
operation()
addComponent(Component)
removeComponent(Component)
getChild(int)
En caso de definir una interfaz para acceder al padre de un componente en la estructura recursiva, se simplifica el
recorrido y la gestión de la estructura compuesta, ya que la referencia al padre facilita ascender por la estructura y borrar un
componente.
El lugar habitual donde definir la referencia al padre es en la clase Component. Las clases Leaf y Composite pueden
heredar la referencia y las operaciones que la gestionan.
Con referencias al padre, es esencial mantener el invariante de que todos los hijos de un compuesto tienen como padre al
compuesto que a su vez los tiene a ellos como hijos. El modo más fácil de garantizar esto es cambiar el padre de un
componente sólo cuando se añade o se elimina a éste de un compuesto.
Otra posible variante del patrón se da cuando se requiere compartir componentes, por ejemplo, para reducir los requisitos
de almacenamiento.
En caso de que se necesite mantener referencias explícitas al padre de cada componente, los hijos tendrían que
almacenar múltiples padres. Pero eso puede llevarnos a ambigüedades cuando se propaga una petición hacia arriba en la
estructura.
Para simplificar la compartición sería necesario adaptar el diseño para evitar guardar los padres. Esto es factible en casos
en los que los hijos puedan evitar enviar peticiones a sus padres externalizando parte de su estado, o todo.
Consecuencias
Ventajas Desventajas
Define jerarquías de clases formadas por objetos primitivos y compuestos. Los Puede hacer que un diseño sea
objetos primitivos pueden componerse en otros objetos más complejos, que a su vez demasiado general. La
pueden ser compuestos y así de manera recursiva. Allí donde el código espere un desventaja de facilitar añadir
objeto primitivo, también podrá recibir un objeto compuesto. nuevos componentes es que
hace más difícil restringir los
Los clientes pueden tratar uniformemente a las estructuras compuestas y a los
componentes de un compuesto.
objetos individuales. Los clientes normalmente no conocen (y no les debería
A veces se requiere que un
importar) si están tratando con una hoja o con un componente compuesto. Esto
compuesto sólo tenga ciertos
simplifica el código del cliente, puesto que evita tener que escribir funciones con
componentes. Con el patrón
instrucciones if anidadas en las clases que definen la composición
Composite, no podemos confiar
Facilita añadir nuevos tipos de componentes. Si se definen nuevas subclases en el sistema de tipos para
Composite o Leaf, éstas funcionarán automáticamente con las estructuras y el código que haga cumplir estas
cliente existentes. No hay que cambiar los clientes para las nuevas subclases de restricciones, por lo que es
Component. necesario realizar
comprobaciones en tiempo de
ejecución.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 46/117
19/1/2021 Patrones de Diseño
Decorator
Problema
Motivación
Un maestro de
Scenario
repostería se
main()
responsabiliza de
elaborar postres
(_galletas
tradicionales, public prepareTradicionalCookies(ApprenticePastryChef) {
apprenticePastryChef.beat();
soufflé, …) para lo this.addBehaviourToBeatTraditionalCookies();
MasterPastryChef apprenticePastryChef.bake();
que bate y hornea
this.addStateToBakeTraditionalCookies();
con diversos prepareTradicionalCookies(ApprenticePastryChef) }
prepareSoufle(ApprenticePastryChef)
utensilios (horno, addBehaviourToBeatTradicionalCookies() public prepareSouffle(ApprenticePastryChef) {
addStateToBakeTraditionalCookies()
reloj, …) con addBehaviourToBeatSouffle()
apprenticePastryChef.beat();
addStateToBakeSouffle() this.addBehaviourToBeatSouffle();
diferentes apprenticePastryChef.bake();
this.addStateToBakeSouffle();
técnicas }
específicas
(cambios de ritmo,
cambios de
Clock
temperatura, …). ApprenticePastryChef Oven
Código de Contraejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/Decorator/decoratorWrongx)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 47/117
19/1/2021 Patrones de Diseño
También interesa analizar otro aspecto relacionado con la granularidad, en este caso, en la clase Scenario, ya que es posible
que se desee elaborar cualquier combinación de los distintos postres.
Es decir, la granularidad de la clase Scenario medida como el número de llamadas a métodos de la clase MasterPastryChef en
función de la cantidad de distintos postres.
Se calcula como la suma del aprendiz (ej. ApprenticePastryChef) y las combinaciones2 de la cantidad de distintos postres
tomadas de n en n, variando n desde uno hasta el número de postres.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 48/117
19/1/2021 Patrones de Diseño
2
Nótese que las combinaciones de m elementos tomados de n en n (m >= n) da lugar a los posibles grupos formados por n
elementos de manera que:
No entran todos los elementos si m > n. Sí pueden entrar todos los elementos si m = n.
No importa el orden.
Intención
invertir en la main()
contratación de
oficiales de
«Director»
cocina específicos MasterPastryChef
que se preparePastries(PastryChef)
responsabilizan
de elaborar «Component»
tradicionales,
beat()
bake()
soufflé, …)
supervisando al
«ConcreteComponent» «Decorator»
aprendiz y ApprenticePastryChef SkilledPastryChef public beat() {
pastryChef.beat();
permitiendo al beat()
bake()
beat()
bake()
}
maestro centrarse
en la
investigación e
«ConcreteDecoratorA» «ConcreteDecorateB»
public beat() { TraditionalSkilledPastryChef FrenhCuisineSkilledPastryChef public bake() {
innovación._ super.beat();
this.addBehaviourToBeatTraditionalCookies(); beat() beat()
super.bake();
this.addStateToBakeSouffle();
bake() bake()
} addBehaviourToBeatTraditionalCookies() addBehaviourToBeatSouffle() }
addStateToBakeTraditionalCookies() addStateToBakeSouffle()
Clock
Oven
getCurrentDate()
setLastTimeUsage()
calculateMinutesBetweenDates()
isReady()
setAlarmDelay()
También interesa analizar otro aspecto relacionado con la granularidad, en este caso, en la clase Scenario, ya que es posible
que se desee elaborar cualquier combinación de los distintos postres.
Es decir, la granularidad de la clase Scenario medida como el número de llamadas a métodos de la clase MasterPastryChef en
función de la cantidad de distintos postres.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 49/117
19/1/2021 Patrones de Diseño
Se calcula como la suma del aprendiz (ej. ApprenticePastryChef) y el método relativo a la responsabilidad de la clase (ej.
preparePastries).
Intención Aplicabilidad
La intención de este patrón es Añadir responsabilidades a objetos individuales en vez de a toda una clase, sin
agregar responsabilidades afectar a otros objetos.
adicionales a un objeto
Añadir responsabilidad que pueda ser retirada.
dinámicamente, proveyendo
una alternativa flexible a la Evitar la extensión mediante herencia cuando ésta no es viable debido a:
subclasificación para Existencia de un gran número de extensiones independientes, que
extender la funcionalidad. producirían una explosión de subclases para permitir todas las
combinaciones.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 50/117
19/1/2021 Patrones de Diseño
ConcreteComponent: clase derivada de Component que define un objeto al que se pueden añadir responsabilidades
adicionales.
Decorator: clase derivada de Component, por lo que define una interfaz que se ajusta a la interfaz de ésta, de manera que
su presencia es transparente a sus clientes. Esta transparencia permite anidar decoradores recursivamente, consiguiéndose
así un número de responsabilidades añadidas. Además, define los comportamientos estándar que se esperan de todas las
clases ConcreteDecorator, tales como:
Mantener una referencia a un objeto Component, que podrá ser un objeto ConcreteComponent u otro Decorator.
Reenviar las peticiones al componente y realizar, opcionalmente, acciones adicionales antes o después del reenvío.
ConcreteDecorator: clase derivada de Decorator que añade alguna responsabilidad al componente. Un ConcreteDecorator
puede definir métodos adicionales y/o variables para ampliar al componente.
Implementación
Variaciones
Se puede prescindir de la clase abstracta Decorator cuando sólo se necesita añadir una responsabilidad. Esta situación
es habitual cuando se está utilizando una jerarquía de clases existente y no diseñando una nueva. En ese caso, se puede
trasladar la responsabilidad de Decorator relativa al reenvío de peticiones al componente a la clase ConcreteDecorator.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 51/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
El patrón Decorator ofrece una manera más flexible de añadir responsabilidades Un diseño que usa el patrón
a los objetos que la utilización de la herencia (múltiple) estática. Con los Decorator suele dar como
decoradores se pueden añadir y eliminar responsabilidades en tiempo de ejecución. resultado sistemas formados
Por el contrario, la herencia requiere crear una nueva clase para cada por muchos objetos pequeños
responsabilidad adicional. Esto da lugar a muchas clases diferentes e incrementa la muy parecidos. Los objetos sólo
complejidad de un sistema. Por otro lado, utilizar diferentes clases se diferencian en la forma en
ConcreteDecorator para una determinada clase ConcreteComponent permite mezclar que están interconectados, y no
responsabilidades. en su clase o en el valor de sus
variables. Aunque dichos
Ofrece un enfoque para añadir responsabilidades que consiste en pagar sólo
sistemas son fáciles de adaptar
por aquello que se necesita. En vez de intentar permitir todas las
por parte de quienes los
funcionalidades inimaginables en una clase compleja y adaptable, se puede
comprenden bien, pueden ser
definir una clase simple y añadir luego funcionalidad incrementalmente con objetos
difíciles de aprender y de
ConcreteDecorator. La funcionalidad puede obtenerse componiendo partes simples.
depurar.
Como resultado, una aplicación no necesita pagar por características que no usa.
Relacionar Estructuras del Tiempo de Acoplamiento Incapacidad para modificar las clases Principio
Compilación y de Ejecución convenientemente Abierto/Cerrado
Facade
Problema
Motivación
reforma de un main()
domicilio
conlleva que el
propietario realice public performAlteration() {
this.bank.arrangeLoan();
diversas tareas this.townHall.arrangeLicense();
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 52/117
19/1/2021 Patrones de Diseño
AcoplamientoWrongFacade2
Intención
para no interactuar
con el resto de
especialistas. public performAlteration() {
brickLayer.takeDownWall();
...
«Facade»
TownHall electrician.installLigtingSystem(); Bank
Contractor
plumber.installFixture();
arrangelicense() ... arrangeLoan()
performAlteration()
carpenter.installMolding();
painter.applyPaint();
}
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 53/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Simplificar el uso de sistemas complejos proporcionando una interfaz más
proveer de una interfaz sencilla sin eliminar las opciones avanzadas. De esta manera puede proveer una
unificada a un conjunto de vista simple por defecto que es suficiente para la mayoría de los clientes, y solo los
interfaces de un subsistema clientes que necesiten más particularizaciones necesitarán mirar tras la fachada.
definiendo una interfaz de
Reducir el acoplamiento entre los clientes y las implementaciones de las clases
más alto nivel que hace más
de un subsistema cuando hay muchas dependencias entre ambos. Al desacoplar
fácil de usar el subsistema.
el subsistema de los clientes y otros subsistemas, promociona la independencia del
subsistema y la portabilidad.
Organizar por capas los subsistemas. Permite definir un punto de entrada para
cada nivel de subsistema. Si los subsistemas son dependientes, se pueden simplificar
las dependencias entre ellos haciéndolos comunicarse entre sí solamente a través de
sus fachadas.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 54/117
19/1/2021 Patrones de Diseño
Director
Facade
SubsystemClass: implementan la funcionalidad del subsistema y llevan a cabo las peticiones solicitadas por el objeto
Facade, aunque para ellas, el objeto Facade sólo será otro cliente más, al que no conocen y del que no tienen una referencia.
Implementación
Variaciones
Puede implementarse el Facade como una interfaz o una clase abstracta, lo cual permite reducir aún más el
acoplamiento entre los clientes y el subsistema, ya que los clientes podrán comunicarse con el subsistema a través de dicha
interfaz y, definir en un momento posterior, los detalles de la implementación de la fachada concreta que será utilizada para
interaccionar con las clases del subsistema.
Consecuencias
Ventajas Desventajas
Flyweight
Problema
Motivación
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 55/117
19/1/2021 Patrones de Diseño
En un torneo de
Scenario
cartas se disputan
mil juegos, y cada
main()
juego se
responsabiliza de
crear las 52
cartas de la
baraja que CardGame
public getCard(Suit, Value) {
precisa, por lo return new StandardCard(suit, value);
getCard(Suit, Value) }
que se necesitará getCard()
almacenar una
gran cantidad de
objetos iguales, es
decir, 52.000 cartas
Card
(mil ases de picas,
mil reyes de
getSuit()
corazones, …) getValue()
isFacedUp()
aunque éstas sean
flip()
constantes y no
cambien.
WildCard
StandardCard
getCard()
getSuit() setCard()
getValue() getSuit()
getValue()
AcoplamientoWrongFlyweight2
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 56/117
19/1/2021 Patrones de Diseño
Si la Scenario
responsabilidad main()
juegos, lo cual
reducirá el número
«FlyWeight»
de objetos Card
utilizados. getSuit()
getValue()
«UnsharedConcreteFlyweight»
«ConcreteFlyWeight» WildCard
StandardCard
getCard()
getSuit() setCard()
getValue() getSuit()
getValue()
Intención Aplicabilidad
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 57/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Aplicable cuando se cumplen todas las siguientes condiciones:
promocionar la compartición
Se utilizan un gran número de objetos idénticos o casi idénticos, existiendo un
para soportar un gran número
alto coste de almacenamiento debido a la gran cantidad de objetos.
de objetos de grano fino
eficientemente. Para todos aquellos objetos casi idénticos, las partes diferentes pueden ser
separadas de las partes similares, permitiendo la compartición de las partes
comunes.
Solución
public getFlyweight() {
if (flyWeight(key) != null)
return flyWeight(key)
FlyWeightFactory FlyWeight
else
newFlyWeight = new ConcreteFlyWeight();
flyWeightPool.add(newFlyWeight); getFlyWeight(key) operation(extrinsicState)
return newFlyWeight;
}
ConcreteFlyWeight UnshredConcreteFlyWeight
intrinsicState allState
operation(extrinsicState) operation(extrinsicState)
ConcreteFlyWeight: clase derivada de FlyWeight que implementa los métodos de la interfaz y permite almacenar el estado
intrínseco, en caso de que lo haya. Un objeto ConcreteFlyWeight debe poder ser compartido, por lo que cualquier estado que
almacene debe ser independiente del contexto del objeto concreto. Es decir, un objeto ConcreteFlyWeight no puede hacer
suposiciones sobre el contexto en el que opera.
UnsharedConcreteFlyWeight: no todas las subclases de FlyWeight necesitan ser compartidas, ya que la interfaz FlyWeight
permite la compartición, pero no fuerza a ella. Los objetos UnsharedConcreteFlyWeight suelen tener objetos
ConcreteFlyWeight como hijos en algún nivel de la estructura de objetos.
FlyWeightFactory: clase para la creación y el control de los objetos ConcreteFlyWeight, que garantiza que éstos se
compartan de manera adecuada. Cuando se solicita un ConcreteFlyWeight, la clase FlyWeightFactory proporciona una
instancia concreta o crea una instancia nueva en caso de que no exista ninguna.
Habitualmente, la clase FlyWeightFactory utiliza un array asociativo por algún código para almacenar los objetos
ConcreteFlyWeight disponibles.
Esto implica algún tipo de recuento de referencias o recogida de basura para el almacenamiento de un peso mosca
cuando ya no es necesario. Sin embargo, si el número de pesos mosca es fijo y pequeño puede ser interesante
mantenerlos de forma permanente.
Director: clase que mantiene una referencia a los objetos FlyWeight y calcula o guarda el estado extrínseco de los mismos.
Implementación
Variaciones
No existen variaciones del patrón.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 58/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
Se consigue un ahorro de almacenamiento, cuyo volumen es una función de Puede introducir costes de
varios factores: la reducción en el número total de instancias lograda mediante la tiempo de ejecución asociados
compartición; la cantidad de estado intrínseco por objeto; y si el estado extrínseco se con la transferencia, búsqueda
calcula o se almacena. y/o computación del estado
extrínseco.
Este ahorro en el caso del torneo de cartas sería el siguiente:
El acoplamiento entre clases
Almacenamiento Wrong
empeora al introducirse nuevas
El número de objetos carta estándar en la clase Scenario (ej. 104) será el clases requeridas por el patrón
producto del número de juegos simultáneos (ej. 2) por el número de cartas para facilitar la compartición.
estándar (ej. StandardCard, 52). Su resultado es de orden cuadrático, O(n2).
Almacenamiento Fine
El número de objetos carta estándar en la clase Scenario (ej. 52) será el número
de cartas estándar (ej. StandardCard, 52). Su resultado es de orden lineal, O(n).
Proxy
Problema
Motivación
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 59/117
19/1/2021 Patrones de Diseño
Un jefe se
Scenario
responsabiliza de
atender las
main()
peticiones de sus
empleados,
concesión de
vacaciones, subidas
de sueldos, … pero Employee
Boss
puede necesitar
Employee(Boss)
ausentarse, en requestHolidays(Date, int)
answerHolidaysRequest(Date, int)
answerSalaryIncreaseRequest()
cuyo caso dejará requestSalaryIncrease()
answerDoctorAppointmentRequest()
requestDoctorAppointment()
desatendidas sus requestInvoiceRefund(int)
answerInvoiceRefundRequest(int)
responsabilidades.
Esto provoca una
dependencia
innecesaria en la
localización del jefe
para que todo siga
su curso.
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 60/117
19/1/2021 Patrones de Diseño
Si se nombra a un
Scenario
representante en
ausencia del jefe
main()
para que centralice
las peticiones de los
empleados, y las
responda siguiendo
«Director»
las instrucciones del Employee
«Subject»
Boss
jefe, las
responsabilidades Employee(Boss)
answerHolidaysRequest(Date, int)
requestHolidays(Date, int)
del jefe no requestSalaryIncrease()
answerSalaryIncreaseRequest()
answerDoctorAppointmentRequest()
quedarán requestDoctorAppointment()
answerInvoiceRefundRequest(int)
requestInvoiceRefund(int)
desatendidas y se
conseguirá una
independencia de la
localización del jefe.
«Proxy» «RealSubject»
ProxyBoss RealBoss
Intención Aplicabilidad
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 61/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Existe una necesidad de una referencia a un objeto más versátil o sofisticada
proporcionar un sustituto o que un simple puntero:
representante de otro objeto
Un Proxy virtual permite crear objetos costosos por encargo, para diferir todo
para controlar el acceso al
el coste de su creación e inicialización hasta que sea realmente necesario usarlo.
mismo.
Un Proxy remoto proporciona un representante local de un objeto situado en
otro espacio de direcciones.
Solución
Subject
Director
request()
Proxy RealSubject
request() request()
public request() {
...
realSubject.request();
...
}
RealSubject: clase que implementa la interfaz Subject y define el objeto real representado por el objeto Proxy.
Proxy: clase que implementa la interfaz Subject y puede sustituir al objeto RealSubject, redirigiendo las llamadas de los
métodos a éste cuando sea apropiado.
Los Proxy virtuales pueden guardar información adicional sobre RealSubject, por lo que pueden retardar el acceso al
mismo cuando se recibe una petición.
Los Proxy remotos son responsables de codificar una petición para enviársela a RealSubject cuando éste se encuentra en
un espacio de direcciones diferente.
Los Proxy de protección comprueban que el Director tenga los permisos de acceso necesarios para realizar una petición
a RealSubject.
Implementación
Variaciones
Si una clase Proxy puede tratar con su sujeto sólo a través de una interfaz abstracta, no hay necesidad de hacer una clase
Proxy para cada clase RealSubject puesto que el Proxy puede tratar de manera uniforme a todas las clases RealSubject. Esta
variación no es posible cuando los objetos Proxy van a crear instancias de RealSubject, ya que en ese caso necesitan
conocer la clase concreta.
Para implementar algunos tipos de Proxy en los que éste se comporta igual que un puntero, se puede aprovechar en lenguajes
como C++ la posibilidad de sobrecarga del operador de acceso a miembros, lo cual permite realizar tareas adicionales
cada vez que se desreferencia un objeto. Esto no es posible cuando se necesita saber exactamente qué operación es llamada ya
que la sobrecarga el operador de acceso a miembros no permite hacer esta distinción.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 62/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
Introduce un nivel de indirección al acceder a un objeto, lo cual tiene muchos Un inconveniente potencial del
posibles usos dependiendo del tipo de Proxy: Proxy remoto es que, como el
cliente no sabe que está
En el caso del Proxy virtual permite diferir la creación del objeto real hasta que
trabajando sobre una red,
éste es necesario. Además, permite realizar optimizaciones sobre cuándo y cómo
podría no estar preparado para
crear el objeto real.
las penalizaciones de tiempo
En el caso del Proxy remoto permite ocultar el hecho de que el objeto real que puedan ocurrir.
reside en un espacio de direcciones diferente, es decir, se puede ocultar la red
al cliente.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 63/117
19/1/2021 Patrones de Diseño
Patrones de Comportamiento
Patrón
Chain of Responsability Command Interpreter Iterator Mediator Mememto Observer State Strategy Template Method Visitor
Tienen que ver con algoritmos y con la asignación de Encapsular aquello que puede variar es el tema de
responsabilidades a objetos para describir el flujo de muchos patrones de comportamiento. Cuando un
control complejo que es difícil de seguir en tiempo de determinado aspecto de un programa cambia con
ejecución, lo que permite olvidarse de éste para frecuencia, estos patrones definen un objeto que
concentrarse simplemente en el modo en que encapsula dicho aspecto. La mayoría de los patrones
interconectan los objetos. tienen dos tipos de objetos: el nuevo objeto que encapsula
el aspecto y el objeto existente que usa el nuevo objeto
creado. Normalmente, si no fuera por el patrón, la
funcionalidad de los nuevos objetos sería una parte
integral de los existentes.
Chain of Responsibility
Problema
Motivación
Un alumno se Scenario
main()
responsabiliza de
interponer una public complainProfessorBehaviour() {
...
reclamación
if(!this.professor.handleComplainAboutExam()) {
Student
if(!this.subjectCoordinator.handleComplainAboutExam()) {
if(!this.dpartamentHeadMaster.handleComplainAboutExam()) {
complainAboutExam() if(!this.educationAffairsViceDean.handleComplainAboutExam()) {
cuando tiene
complainAboutDepartamentRule()
if(!this.dean.handleComplainAboutExam()) {
...
}
alguna queja,
sobre un examen o Profesor
StudentDefender DepartamentHeadMaster Dean
SubjectCoordinator
EducationAffairsViceDean Provost
una regla de un
handleComplainAboutExam() handleComplainAboutExam() handleComplainAboutExam() handleComplainAboutExam() handleComplainAboutExam()
handleComplainAboutExam() handleComplainAboutExam()
handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule()
departamento o …,
pero dependiendo
del tipo de
reclamación,
deberá conocer y
discernir a qué
miembro de la
cadena de
responsabilidad
debe presentar la
reclamación,
profesor o
coordinador de la
asignatura o
Esto complica la comprensión de su comportamiento y tiende a crecer a medida que
director de
surgen nuevos miembros de la cadena de responsabilidad.
departamento o jefe
de estudios o
director de escuela
o rector o defensor
del alumno …
Código de Contraejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/ChainOfResponsibility/chainOfResponsibilityWrong)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 64/117
19/1/2021 Patrones de Diseño
Intención
Si la Scenario
main()
responsabilidad
de estudiante public complainAboutExam() {
...
«Director»
Student
«Handler»
ClaimSolver
claimSolver.handleComplainAboutExam();
incluye }
... complainAboutExam()
complainAboutDepartamentRule()
handleComplainAboutExam()
handleComplainAboutDepartamentRule()
únicamente la
interposición de
«ConcreteHandlerC» «ConcreteHandlerE» «ConcreteHandlerG» «ConcreteHandlerD» «ConcreteHandlerF»
«ConcreteHandlerB» «ConcreteHandlerA»
DepartamentHeadMaster Dean StudentDefender EducationAffairsViceDean Provost
SubjectCoordinator Profesor
la reclamación
handleComplainAboutExam() handleConplainAboutExam()
handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule() handleComplainAboutDepartamentRule()
ante el primer
miembro de la
cadena de
responsabilidad y
otros, miembros
de la cadena, se
responsabilizan
por separado de
elevar la
reclamación al
siguiente
miembro de la
cadena cuando no
pueden/saben
resolverla,
ninguna clase será
compleja y se
evitará la tendencia
a crecer.
Código de Ejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/ChainOfResponsibility/chainOfResponsibilityFine)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 65/117
19/1/2021 Patrones de Diseño
El acoplamiento de la clase Student (ej. 1) La cohesión de la -La granularidad de los métodos de la clase
depende del tipo de la clase resolutora (ej. clase Student es Student (ej. 1) depende del tipo de la clase
ClaimSolver, 1). adecuada puesto resolutora (ej. ClaimSolver, 1).
que asume una
Su resultado es de orden constante, O(1).
única Su resultado es de orden constante, O(1).
responsabilidad,
centrada en la
interposición de la
reclamación,
colaborando
únicamente con el
servicio del primer
miembro de la
cadena de
responsabilidad,
que a su vez se
apoyará en el
servicio prestado
por el resto de
miembros de la
cadena para elevar
la reclamación
cuando sea preciso.
Intención Aplicabilidad
La intención de este patrón es Hay más de un objeto que puede manejar una petición y el manejador no se
evitar acoplar al emisor de conoce a priori, sino que debería determinarse automáticamente.
una petición a su receptor,
Se quiere enviar una petición a un objeto entre varios sin especificar
dando a más de un objeto la
explícitamente el receptor.
posibilidad de responder la
petición. Se basa en El conjunto de objetos que pueden tratar una petición debería ser
encadenar los objetos especificado dinámicamente.
receptores y pasar la petición
a lo largo de la cadena hasta
que es procesada por algún
objeto.
Solución
ConcreteHandler: clase
public handleRequest() {
derivada de Handler que trata
if(can handle)
Director
Handler
handlerMethod(); las peticiones de las que es
else responsable. Si puede manejar
handleRequest() successor.handlerequest();
} la petición, lo hace; en caso
contrario, la reenvía a su
sucesor.
ConcreteHandlerA ConcreteHandlerB
handleRequest() handleRequest()
Director: clase que inicia la petición a un objeto _ConcreteHandler- de la cadena, habitualmente, el primero.
No tiene conocimiento explícito de quién tratará la petición – se dice que la petición tiene un receptor implícito.
Implementación
Variaciones
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 66/117
19/1/2021 Patrones de Diseño
Para reenviar la petición a lo largo de la cadena, y para garantizar que los receptores permanecen implícitos, cada objeto de
la cadena comparte una interfaz común para procesar peticiones y para acceder a su sucesor en la cadena.
Utilizar referencias a objetos existentes. Por ejemplo, las referencias al padre en una jerarquía de parte-todo pueden
definir el sucesor de una parte. Usar los enlaces existentes es posible cuando éstos permiten la cadena que necesitamos. Nos
evita tener que definir explícitamente nuevos enlaces y ahorra espacio.
Definir nuevos enlaces. Si no hay referencias preexistentes para definir una cadena, o los que existen no reflejan la cadena
de responsabilidad que necesita nuestra aplicación, habrá que definir enlaces nuevos. En este caso, Handler no sólo
define la interfaz para las peticiones, sino que normalmente también se encarga de mantener el sucesor. Eso
permite que Handler proporcione una implementación predeterminada de handleRequest que reenvíe la petición al
sucesor (si hay alguno). Si una subclase de ConcreteHandler no está interesada en dicha petición, no tiene que redefinir la
operación de reenvío, puesto que la implementación predeterminada la reenvía incondicionalmente.
En su forma más simple, una petición es una invocación a una operación insertada en el código. Esto resulta
conveniente y seguro, pero entonces sólo se pueden reenviar el conjunto prefijado de peticiones que define la clase Handler.
Una alternativa más flexible consiste en usar una única función handleRequest que reciba un código de petición
como parámetro, lo cual permite un número arbitrario de peticiones. Pero requiere que el emisor y el receptor se pongan
de acuerdo sobre cómo debe codificarse la petición y se necesitan sentencias condicionales para despachar la petición en
función de su código. Uno de los principales inconvenientes de este enfoque es que no hay un modo seguro de pasar los
parámetros con respecto al tipo, por lo que éstos deben ser empaquetados y desempaquetados manualmente.
Una alternativa para resolver el problema del paso de parámetros consiste en utilizar objetos aparte para las peticiones que
empaqueten los parámetros de la petición. Una clase Petición puede representar peticiones explícitamente, y se pueden
definir nuevos tipos de peticiones mediante herencia. Las subclases pueden definir diferentes parámetros. Los manejadores
deben conocer el tipo de petición para acceder a estos parámetros.
Consecuencias
Ventajas Desventajas
Libera a un objeto de tener que saber qué otro objeto maneja una petición. Un Dado que las peticiones no
objeto sólo tiene que saber que una petición será manejada “de forma apropiada”. tienen un receptor explícito, no
Ni el receptor ni el emisor se conocen explícitamente entre ellos, y un objeto de la hay garantía de que sean
cadena tampoco tiene que conocer la estructura de ésta. manejadas ya que la petición
puede alcanzar el final de la
Como resultado, se puede simplificar las interconexiones entre objetos. En
cadena sin haber sido
vez de que los objetos mantengan referencias a todos los posibles receptores, solo
procesada.
tienen una única interfaz a su sucesor.
En caso de haber un gran
Ofrece una flexibilidad añadida para repartir responsabilidades entre objetos.
número de mensajes y muchas
Se pueden añadir o cambiar responsabilidades para tratar una petición
etapas de redireccionamiento
modificando la cadena en tiempo de ejecución. Esto se puede combinar con la
en la cadena, podría tener lugar
herencia para especializar los manejadores estáticamente.
un alto intercambio baldío de
mensajes, por lo que el
rendimiento del sistema
podría degradarse.
Poner a funcionar los mecanismos de Reusabilidad por Añadir funcionalidad mediante herencia Principio
reutilización composición, Abierto/Cerrado
herencia y/o
parametrización
Command
Problema
Motivación
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 67/117
19/1/2021 Patrones de Diseño
En un restaurante
Scenario
hay distintos tipos
de empleados: main()
camareros,
cocineros,
bármanes, … Un
camarero se Restaurant
responsabiliza de
atender las attendToCustumersAtLunchTime()
attendToCustomersAtDinnerTime()
comandas de un
cliente con el
mismo algoritmo,
informar al cliente
Waiter Chef
de las opciones
Barman
disponibles en la Waiter(Chef, Barman) preparateSalad()
serveDishOfTheDay() preparateEggs()
carta y sus prepareVermouth()
serveConbinationPlate() preparateFries()
prepareBloodyMary()
ingredientes, anotar serveVermouth() preparateSoup()
cleanBar()
serveBloodyMary() preparateSteak()
la comanda, generateRandomEmployeeld() clanKitchen()
dirigirse al interior
(a la cocina o a la
barra o …) para
encargar la public serveDishOfTheDay() {
comanda al ...
int chefid = this.generateRandomEmployeeld();
empleado adecuado
this.chefs[chefid].prepareSoup();
(que sepa this.chefs[chefid].prepareSteak();
prepararla o …), this.chefs[chefid].prepareFries();
...
esperar a que
}
prepare la
comanda, servir la
comanda al cliente,
… pero
dependiendo de la
opción de la carta
seleccionada por
el cliente,
solicitará
distintas
preparaciones a
distintos tipos de
empleado, Esto complica la comprensión de su comportamiento y tiende a crecer a medida que
cocinero o surgen nuevas opciones en la carta.
barman o …
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 68/117
19/1/2021 Patrones de Diseño
Intención
Si la Scenario
responsabilidad main()
de camarero
incluye «Director»
Restaurant
únicamente la attendToCustumersAtLunchTime()
attendToCustomersAtDinnerTime()
colocación de la
comanda en un «Invoker»
«Command»
public serve() { Order
lugar acordado y
Waiter
order.serve();
} serve()
serve(Order)
generateRandomNumber()
la posterior
recogida de la
«AbstractCommandA» «AbstractCommandB»
comanda ChefOrder BarmanOrder
preparada para
ChefOrder(Cheef) BarmanOrder(Barman)
getChef() getBarman()
servírsela al
cliente, y otros, «Receiver»
Chef «Receiver»
«ConcreteCommandAA» «ConcreteCommandAB» «ConcreteCommandBB» «ConcreteCommandBA»
cocineros y preparateSalad() DishOfTheDayOrder CombinationPlateOrder BloodyMaryOrder VermouthOrder
Barman
preparateEggs()
prepareVermouth()
bármanes, se
preparateFries() DishOfTheDayOrder(Chef) CombinationPlateOrder(Chef) BloodyMaryOrder(Barman) VermouthOrder(Barman)
prepareBloodyMary()
preparateSoup() serve() serve() serve() serve()
cleanBar()
preparateSteak()
responsabilizan
clanKitchen()
por separado de
escoger la
public serve() {
...
this.getChef().prepareSoup();
comanda que van this.getChef().prepareSteak();
this.getChef().prepareFries();
...
a preparar según }
sus condiciones y
dejarla
preparada en el
lugar acordado,
habrá dos equipos
de trabajo
independientes y
mucho menos
trabajo para el
camarero.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 69/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Parametrizar objetos con una acción a realizar. Los objetos Command son un
encapsular una petición como sustituto orientado a objetos para las funciones callback.
un objeto, permitiendo de ese
Especificar, poner en cola y ejecutar peticiones en diferentes instantes del
modo parametrizar clientes
tiempo. Un objeto Command puede tener un tiempo de vida independiente de la
con diferentes peticiones,
petición original. Si se puede representar el receptor de una petición en una forma
colas o solicitudes registradas,
independiente del espacio de direcciones, entonces se puede transferir un objeto
y apoyar las operaciones de
Command con la petición a un proceso diferente y llevar a cabo la petición allí,
deshacer.
desacoplando la fuente de una petición del objeto que la cumple.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 70/117
19/1/2021 Patrones de Diseño
Receiver
Command
Invoker
action1()
execute()
action2()
ConcreteCommandA ConcreteCommandB
execute() execute()
Invoker: clase que solicita a través de la interfaz Command que se ejecute la operación.
Receiver: clase que sabe cómo llevar a cabo las operaciones asociadas a una petición.
Implementación
Variaciones
Un comando puede tener un rango diverso de habilidades:
Se puede limitar a definir un enlace entre un receptor y las acciones que lleva a cabo la petición.
Se puede ocupar de implementar todas las acciones ella misma sin delegar para nada en el receptor. Este último
extremo resulta útil cuando queremos definir comandos que sean independientes de las clases existentes, cuando no existe
ningún receptor adecuado o cuando un comando conoce implícitamente a su receptor.
En algún punto entre estos dos extremos se encuentran los comandos que tienen el conocimiento suficiente para
encontrar dinámicamente sus receptores.
Los comandos pueden permitir capacidades de deshacer y repetir si proveen un modo de revertir su ejecución. Una
clase ConcreteCommand podría necesitar almacenar información de estado adicional para hacer esto. Este estado puede
incluir:
El objeto Receiver, el cual es quien realmente realiza las operaciones en respuesta a la petición;
Cualquier valor original de Receiver que pueda cambiar como resultado de manejar la petición. El receptor debe
proporcionar operaciones que permitan al comando devolver el receptor a su estado anterior.
La histéresis (tendencia de un material a conservar una de sus propiedades, en ausencia del estímulo que la ha generado)
puede ser un problema a la hora de garantizar un mecanismo de deshacer/rehacer fiable, que preserve la semántica.
Los errores se pueden acumular a medida que se ejecutan y deshacen los comandos repetidamente, de manera que el
estado de una aplicación finalmente difiera de sus valores originales. Por tanto, puede ser necesario guardar más
información con el comando para asegurar que los objetos son devueltos a su estado original
Se pueden permitir diferentes niveles de deshacer/rehacer. Para permitir un nivel, sólo es necesario guardar el último
comando que se ejecutó. Para múltiples niveles es necesario guardar un historial de los comandos que han sido
ejecutados, donde la máxima longitud de la lista determina el número de niveles permitidos. Recorrer la lista hacia atrás
deshaciendo los comandos cancela sus efectos; recorrerla hacia delante ejecutando los comandos los rehace.
Un comando anulable puede que necesite ser copiada antes de ser guardada en el historial. Puesto que el objeto
Command que llevó a cabo la petición original más tarde ejecutará otras peticiones, la copia es necesaria para distinguir
entre diferentes invocaciones del mismo comando si su estado puede variar entre invocaciones sucesivas. En caso de que
el estado del comando no cambie tras su ejecución no es necesario realizar la copia, basta con guardar en el historial una
referencia al comando.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 71/117
19/1/2021 Patrones de Diseño
Este tipo de comandos no tienen ningún receptor explícito, sino que son los comandos que contiene las que definen su
propio receptor.
Si el MacroCommand soporta la función deshacer, todos los comandos internos también deben soportarla. Cuando se
llama a la función para invertir el comando, esta llamada debe ser redirigida a los hijos en el orden inverso de la operación
execute.
Consecuencias
Ventajas Desventajas
Es fácil añadir nuevos comandos, ya que no hay que cambiar las clases existentes.
Interpreter
Problema
Motivación
Un operador se
Scenario
responsabiliza de
main()
manejar un
aparato complejo
siguiendo una
serie de public performCompositeScriptForStarting(Machine machine) {
this.performOperation(machine, "A");
protocolos, this.performOperation(machine, "B");
this.performOperation(machine, "C");
protocolo de }
mañana o de tarde Operator
debe saber
ejecutar
manualmente. Machine
execute(String)
Código de Contraejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/Interpreter/interpreterWrong)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 72/117
19/1/2021 Patrones de Diseño
Intención
Si la Scenario
responsabilidad main()
de operador
incluye
«Director»
public performProtocol() {
únicamente la sript.execute(machine);
Operator
}
solicitud de performProtocol(Script, Machine)
ejecución
automática del «Context» «AbstractExpression»
Machine Script
protocolo
execute(String) execute(Machine)
(protocolo de
mañana, protocolo
de tarde, …) y otros, «TerminalExpression» «NonTerminalExpression» «NonTerminalExpression» public execute(Machine) {
OperationScript IterativeScript CompositeScript for (Script script : this.scripts) {
scripts, se OperationScript(String) IterativeScript(Script, int) addScript(Script) }
script.execute(machine);
responsabilizan
execute(Machine) execute(Machine) execute(Machine) }
por separado de
cómo se public execute(Machine) {
for (int times = 0; times<this.times; times++) {
interpretan los
public execute(Machine) { «NonTerminalExpression» «NonTerminalExpression»
machine.execute(this.name); this.script.execute(machine); MorningProtocolScript EveningProtocolScript
} }
protocolos en }
operaciones
simples y/o
compuestas,
ninguna clase será
compleja y se
evitará la tendencia
a crecer.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 73/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es, Hay un lenguaje que interpretar y se pueden representar las sentencias del
dado un lenguaje, definir una lenguaje como árboles sintácticos abstractos.
representación de su
Hay un tipo de problemas que ocurren con cierta frecuencia, y es posible
gramática junto con un
expresar las apariciones de esos problemas como instrucciones de un lenguaje
intérprete que utiliza la
simple, para el cual se puede construir un intérprete que sea capaz de resolver estos
representación para
problemas mediante la interpretación de dichas instrucciones.
interpretar sentencias del
lenguaje. El patrón Interpreter funciona mejor cuando:
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 74/117
19/1/2021 Patrones de Diseño
AbstractExpression: declara la
Scenario
interfaz para interpretar, que es
común a todos los nodos del
main()
árbol sintáctico abstracto.
Director
AbstractExpression
Contex
interpret(Context)
TerminalExpression NonTerminalExpression
interpret(Context) interpret(Context)
TerminalExpression: clase derivada de AbstractExpression que implementa la interfaz para interpretar asociada con los
símbolos terminales de la gramática.
Se necesita una instancia de esta clase para cada símbolo terminal de una expresión.
NonTerminalExpression: clase derivada de AbstractExpression que define el comportamiento de los objetos asociados con
los símbolos no terminales de la gramática, es decir, para las reglas de la gramática, que pueden estar formadas a su vez
por otras reglas o por expresiones terminales.
Mantiene variables de instancia de tipo AbstractExpression para cada uno de los símbolos que contiene la regla que
representa.
Implementa la interfaz para interpretar asociada con los símbolos no terminales de la gramática. Normalmente, esta
implementación consiste en llamarse a sí misma recursivamente sobre las variables de instancia que representa.
Director: clase que construye o recibe un árbol sintáctico abstracto que representa una determinada sentencia del
lenguaje definido por la gramática, y que invoca a la operación de interpretar con el contexto adecuado.
Implementación
Variaciones
El patrón Interpreter no especifica cómo crear un árbol sintáctico abstracto ni se ocupa de llevar a cabo el análisis
sintáctico. El árbol sintáctico abstracto puede ser creado mediante un analizador sintáctico dirigido por una tabla, mediante
un analizador sintáctico (normalmente recursivo descendente) hecho a mano o directamente por el Director.
En caso de que se vaya a crear un intérprete que realice múltiples operaciones sobre los árboles sintácticos abstractos,
para evitar definir estas operaciones en cada clase de la gramática, será preferible utilizar el patrón Visitor.
En aquellas gramáticas cuyas sentencias tengan muchas repeticiones de uno o varios símbolos terminales, puede ser
beneficioso compartir una única copia de dichos símbolos. Las gramáticas de los programas software son buenos ejemplos
de ello.
Los nodos terminales generalmente no guardan información sobre su posición en el árbol sintáctico abstracto.
Los nodos padre les pasan cualquier información de contexto que necesiten para llevar a cabo la interpretación,
incluida su posición en el árbol sintáctico abstracto.
Por tanto, se da una distinción entre estado compartido (intrínseco) y estado recibido (extrínseco), que permite utilizar el
patrón FlyWeight.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 75/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
El uso de clases para representar las reglas de la gramática facilita realizar Las gramáticas complejas con
cambios o extensiones de ésta mediante herencia. Esto permite modificar muchas reglas son difíciles de
incrementalmente las expresiones existentes y definir otras nuevas como mantener, ya que el patrón
variaciones de las antiguas. Interpreter define al menos una
clase para cada regla de la
Permite incluir nuevos métodos en la interfaz Expression para añadir nuevas
gramática (las reglas que se
maneras de interpretar expresiones aumentando la funcionalidad. Para
hayan definido usando BNF3
conseguir mayor flexibilidad sin afectar las clases de la gramática se recomienda
pueden necesitar varias clases).
considerar la utilización del patrón Visitor.
Cuando se da esta circunstancia,
se pueden aplicar otros patrones
de diseño para mitigar el
problema, pero se recomienda
considerar el uso de otras
técnicas más adecuadas como
los generadores de
analizadores sintácticos o de
compiladores.
3 La notación de Backus-Naur,
también conocida por sus
denominaciones inglesas
Backus-Naur form (BNF),
Backus-Naur formalism o
Backus normal form, es un
metalenguaje usado para
expresar gramáticas libres de
contexto.
Iterator
Problema
Motivación
Un cliente se Scenario
responsabiliza de
main()
comprar muebles
para una
estancia,
dormitorio o jardín Customer
distintos criterios
de organización
de sus plantas, FurnitureStore
por estancia de la
addFloor(Floor)
casa o por tamaño distributeFurnitureInFloors()
getFloors()
de los muebles o … getFurniture()
localizar los
muebles para la
estancia que le Esto complica la comprensión de su comportamiento y tiende a crecer a medida que
interesa. surgen nuevos criterios de organización.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 76/117
19/1/2021 Patrones de Diseño
Intención
Si la Scenario
responsabilidad main()
de cliente incluye
únicamente la «Director»
Customer
muebles para un
tipo de estancia y «Aggregate»
FurnitureStore
otros,
«Iterator»
ShopAssistant
addFloor(Floor)
dependientes, se
distributeFurnitureInFloors()
nextProduct()
getFloors()
hasMoreProducts()
getFurniture()
responsabilizan
createShopAssistant()
por separado de
conocer el criterio «ConcreteAggregateA»
RoomOrganizedFurnitureStore
«ConcreteAggregateB»
SizeOrganizedFurnitureStore
Furniture Floor «ConcreteIteratorA»
RoomOrganizedShopAssistant
«ConcreteIteratorB»
SizeOrganizedSopAssistant
de organización
getName() addFurniture(Furniture)
distributeFurmitureInFloors() distributeFurmitureInFloors() getRoom() getFurniture() nextProduct() nextProduct()
createShopAssistant() createShopAssistant() getSize() getFurnitureType() hasMoreProducts() hasMoreProducts()
de la tienda y de
localizar los
muebles, ninguna
clase será compleja
y se evitará la
tendencia a crecer.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 77/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Acceder al contenido de un objeto agregado, tal como una lista, sin exponer su
proveer una forma de acceder representación interna.
secuencialmente a los
Permitir varias maneras de recorrer los elementos de los objetos agregados:
elementos de un objeto
agregado sin exponer su Pudiendo coexistir varios recorridos en espera sobre el mismo objeto
representación subyacente. agregado, llevados a cabo por el mismo o distintos clientes.
Sin afectar la interfaz del objeto agregado con las operaciones para llevar a
cabo los diversos recorridos, incluso si se pudiera anticipar los que se
necesitan.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 78/117
19/1/2021 Patrones de Diseño
Scenario
Iterator: declara la interfaz
para recorrer los elementos y
main()
acceder a ellos.
Director
Iterator
Aggregate
first()
next()
createIterator()
isDone()
currentItem()
ConcreteIteratorA ConcreteIteratorB
ConcreteAggregateA ConcreteAggregateB
first() first()
next() next()
createIterator() createIterator()
isDone() isDone()
currentItem() currentItem()
Como mínimo, define los métodos para la navegación, recuperación y validación: first, next, isDone y currentItem.
En agregados ordenados podría añadir previous para posicionar el iterador en el elemento anterior; y
En colecciones ordenadas o indexables aplicando algún criterio, skipTo para posicionar el iterador en un objeto que cumpla
el criterio especificado.
ConcreteIterator: clase derivada de Iterator que implementa la interfaz y mantiene la posición actual en el recorrido
del ConcreteAggregate.
Normalmente las instancias son creadas por ConcreteAggregate. De hecho, debido al alto acoplamiento con dicha clase, la
clase ConcreteIterator es a menudo una clase interna de ConcreteAggregate.
ConcreteAggregate: clase derivada de Aggregate que implementa la interfaz para devolver una instancia del
ConcreteIterator apropiado.
Implementación
Variaciones
Un ConcreteIterator puede ser interno o externo dependiendo de quién controla la iteración:
Los iteradores externos proporcionan métodos para que los clientes naveguen por el objeto agregado. Es decir, los
clientes que utilizan un iterador externo deben avanzar en el recorrido demandando explícitamente el siguiente
elemento del agregado al iterador.
Los iteradores internos recorren los elementos llevando a cabo alguna acción solicitada por el cliente. Es decir, el
cliente entrega al iterador interno una operación a realizar, y el iterador aplica la operación a cada elemento del
agregado.
Si el algoritmo de recorrido necesita acceder a las variables privadas del agregado, para evitar que el iterador viole
la encapsulación de éste, el propio agregado puede definir el algoritmo y utilizar el iterador para almacenar sólo el
estado del recorrido. Este tipo de iteradores se conocen como cursor, ya que se limitan a señalar la posición actual en el
agregado. Los clientes invocarán sobre el agregado la operación next con el cursor como un argumento y la operación next
cambiará el estado del cursor.
Si el algoritmo de recorrido se define en el iterador, es más fácil usar diferentes algoritmos de iteración sobre el
mismo agregado o reutilizar el mismo algoritmo sobre diferentes agregados.
Puede ser peligroso modificar un agregado mientras un iterador lo está recorriendo. Dependiendo de la manera de
gestionar esta circunstancia, un ConcreteIterator puede ser estático o dinámico:
Los iteradores estáticos crean una imagen del agregado en el momento de ser creados y hacen referencia a esa copia
mientras son utilizados.
Es una solución sencilla pero demasiado costosa como para ser empleada siempre.
Los iteradores dinámicos hacen referencia directamente al agregado subyacente, por lo que deben garantizar que
siempre reflejan su estado.
Hay muchas maneras de implementar iteradores robustos. La mayoría lo hacen registrando los iteradores con el
agregado. En la inserción o borrado, el agregado o bien ajusta el estado interno de los iteradores que ha producido, o se
mantiene información internamente para asegurar el recorrido adecuado.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 79/117
19/1/2021 Patrones de Diseño
Los iteradores nulos son iteradores degenerados que facilitan el recorrido de agregados con estructura de árbol, ya
que permiten implementar el recorrido sobre una estructura compuesta de un modo uniforme. En cada punto del
recorrido se puede pedir el elemento actual a un iterador para sus hijos. Los elementos Composite devuelven, como norma
general, un iterador concreto. Pero los elementos Leaf devuelven una instancia de iterador nulo, que se caracterizan porque su
operación isDone siempre se evalúa a verdadero. De esta manera es posible utilizar la recursividad para visitar todos los
nodos del árbol.
Consecuencias
Ventajas Desventajas
Permite variaciones en el recorrido de un agregado, es decir, agregados Pueden crear una ilusión de
complejos pueden ser recorridos de múltiples maneras definiendo nuevas subclases estructuras ordenadas. Si un
de Iterator. conjunto no soporta la
ordenación, su iterador podría
Permite tener varios recorridos simultáneos sobre un agregado, ya que cada
proporcionar los elementos en
iterador mantiene su propio estado del recorrido.
una secuencia arbitraria que
Los Iteradores simplifican la interfaz del agregado ya que la interfaz de podría cambiar con el tiempo. Si
recorrido del Iterador obvia la necesidad de una interfaz similar en el agregado. no se tiene en cuenta este hecho,
La posibilidad de definir una interfaz uniforme para recorrer distintos tipos se podría estar presuponiendo
de agregados simplifica mucho el uso de colecciones y permite utilizar el una coherencia en la estructura
polimorfismo cuando se trabaja con ellas. subyacente que podría provocar
problemas en los clientes.
Mediator
Problema
Motivación
En un encuentro Scenario
getRivalTeamld()
participantes
Match(SeverityLevel)
getTeammates()
play()
informTeamMembersAboutAnswer()
(jugadores, capitanes,
entrenadores, …) que Player
de
requestPenalti()
requestMassage()
answerYesNoRequest()
[red]responsabilizarse
generateRandom(int, boolean)
de sus funciones
individuales, y
Captain
Coach
performCoinToss() Physiotherapist
requestSubstitution()
también de chooseHeadsOrTails()
chooseGoal()
answerYesNoRequest()
answerSubstitutionRequest()
answerMassageRequest() requestMassage()
answerYesNoRequest()
coordinarse a la hora
provideFinalAnswerAfterConsultingTeamMates()
generateRandom(int, boolean)
informTeamMembersAboutGoal()
de tomar decisiones
sobre el reparto inicial SevereCaptain PermissiveCaptain PermissivePlayer SeverePlayer PermissiveCoach SevereCoach
de campos, o si es generateRandom(int, boolean) generateRandom(int, boolean) generateRandom(int, boolean) generateRandom(int, boolean) generateRandom(int, boolean) generateRandom(int, boolean)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 80/117
19/1/2021 Patrones de Diseño
permisividad* más o
Esto complica la comprensión de su comportamiento y tiende a crecer a medida que
menos severo a la hora
surgen nuevos tipos de participantes que tendrán que intervenir en la coordinación.
de decidir.
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 81/117
19/1/2021 Patrones de Diseño
En un encuentro Scenario
deportivo, la main()
solución más
habitual es
nombrar un «Director»
Match «Collegue»
árbitro para TeamMember
Match(Referee)
coordinar y tomar play()
decisiones sobre
el partido, con un
criterio de
«Mediator»
«ConcreteCollegueA» Referee
tipo de participante
se centre en sus
«ConcreteCollegueAA»
responsabilidades Captain
«ConcreteColleagueB»
Coach
Physiotherapist
«ConcreteMediatorB»
PermissiveReferee
«ConcreteMediatorA»
SevereReferee
individuales chooseHeadsOrTails()
requestSubstitution() givetMassage() generateRandom(int, boolean) generateRandom(int, boolean)
chooseGoal()
evitando la
necesidad de que
todos los
participantes
tengan que
interactuar entre
ellos para
coordinarse en la
toma de decisiones.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 82/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Simplificar la comunicación entre un conjunto de objetos que se comunican
encapsular en un único objeto con reglas bien definidas, pero de manera compleja. Es decir, objetos cuyas
la manera en la que interdependencias no están estructuradas y son difíciles de entender.
interactúan un conjunto de
Permitir reutilizar objetos evitando que éstos se refieran a otros muchos
objetos. De esta manera se
objetos con los que se comunican.
consigue promover un menor
acoplamiento al evitar a los Permitir que un comportamiento que está distribuido entre varias clases
objetos referirse pueda ser particularizado sin necesidad de muchas subclasificaciones.
explícitamente unos a otros,
así como permitir variar su
interacción de forma
independiente.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 83/117
19/1/2021 Patrones de Diseño
Collegue Mediator
ConcreteMediatorB ConcreteMediatorA
ConcreteColleagueB ConcreteCollegueA
ConcreteMediator: clase derivada de Mediator que define el comportamiento cooperativo coordinando objetos Colleague.
ConcreteColleague: clase derivada de Colleague que define el comportamiento para comunicarse con el objeto Mediator.
Cada Colleague se comunica con su Mediator cada vez que, de no existir éste, se hubiera comunicado con otro Colleague.
Implementación
Variaciones
La clase abstracta Mediator se puede omitir si los colegas siempre trabajan sólo con un mediador.
Se puede implementar el mediador como un observador, utilizando el patrón Observer. Las clases colegas harán las
veces de sujetos, enviando notificaciones al mediador cada vez que cambie su estado; y el mediador responderá
propagando los efectos del cambio a otros colegas.
Se puede definir en el mediador una interfaz de notificación especializada que permite a los colegas ser más
directos en su comunicación, de tal manera que cuando un colega se comunica con el mediador, se pasa a sí mismo como
argumento permitiendo así al mediador identificar al emisor.
Consecuencias
Ventajas Desventajas
Localiza el comportamiento que de otro modo estaría distribuido entre varios La encapsulación de protocolos
objetos. El cambio de este comportamiento requiere únicamente subclases de y la centralización de
mediador, pudiendo ser reutilizadas las clases colegas tal cual, reduciéndose así la comportamiento específico de la
necesidad de subclasificación. aplicación pueden convertir al
objeto mediador en un objeto
Esto permite enfocarse en cómo interactúan los objetos de un sistema más
más complejo que cualquier
allá de su comportamiento individual y simplificar el mantenimiento de la
colega individual y hacer de él
estrategia general de comunicación puesto que ésta es responsabilidad
un monolito difícil de
exclusiva del mediador.
mantener.
Promueve el desacoplamiento entre colegas. Se pueden variar y reutilizar las
clases colega y mediador de forma independiente.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 84/117
19/1/2021 Patrones de Diseño
Memento
Problema
Motivación
responsabiliza de main()
recuperar una
versión anterior
del plan, se PlanArchive
titleLists
responsabiliza partisipantsLists
detailsLists
también de registry(List.String, List.List.String, List.List.String)
undo(List.String, List.List.String, List.List.String)
proporcionar a redo(List.String, List.List.String, List.List.String)
isUndoable()
un archivo isRedoable()
setTitleAndParticipantsAndDetails(List.String, List.List.String, List.List.String)
aquellos
elementos del
plan que pueden
public undo(title, participants, details) {
this.firstPrevious++;
setTitleAndParticipantsAndDetails(title,participants, details); Plan
ser modificados y } title
}
y así poder
consultarlos Esto complica la comprensión de su comportamiento y tiende a crecer a medida que
posteriormente. surgen nuevos elementos del plan que pueden ser modificados y no se pueden deducir a partir
de otros.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 85/117
19/1/2021 Patrones de Diseño
Intención
Si la
responsabilidad
de persona
incluye
únicamente la
creación y
modificación de
planes, y otros,
planes, se
responsabilizan
por separado de
proporcionar a
un archivo una
copia de aquellos
elementos del
plan que pueden
ser modificados y
no se pueden
deducir a partir
de otros (título,
participantes y
detalles), ninguna
clase será compleja
y se evitará la
tendencia a crecer,
y se preservará la
encapsulación del
plan.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 86/117
19/1/2021 Patrones de Diseño
Scenario
main()
public createPlan() {
...
this.plan=new Plan(title, date, participants, details);
«Director»
this.planActive.regitry(); Person public undoPlanModification() {
} this.planArchive.undo(this.plan);
createPlan()
public modifyPlan(Plan plan) { modifYPlan() public redoPlanMotivation() {
plan.removeDetail(detailToRemove); undoPlanModifiation() this.planArcive.redo(this.plan);
this.planArchive.registry(); redoPlanModification() }
reviewAllPlanVersions()
plan.addParticipant(participantToAdd);
this.planArchive.registry(this.plan.getTitle();
}
«Caretaker»
PlanArchive
planVersions
registry()
undo()
redo()
isUndoable()
isRedoable()
«Originator»
Plan
title
public undo() {
date this.firstPrevious++;
participants this.plan.setPlanVersion(
details this.planVersions.get(this.firrstPrevious));
coordinator }
secretary
public redo() {
createPlanVersion() this.firstPrevious--;
setPlanVersion(PlanVersion) this.plan.setPlanVersion(
setTitle(String)
this.planVersions.get(this.firrstPrevious));
addParticipant(String)
removeParticipant(String) }
addDetail(String)
removeDetail(String)
public createPlanVersion() {
return new PlanVersion(this.title,
this.participants,
this.details)
«Memento»
}
PlanVersion
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 87/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es, Aplicable cuando se cumplen las dos siguientes condiciones:
sin violar la encapsulación,
Se necesita guardar una instantánea del estado interno de un objeto (o de
capturar y externalizar el
parte de éste) para poder restaurar el objeto a dicho estado posteriormente.
estado interno de un objeto de
Tiene gran utilidad cuando se implementan mecanismos de deshacer que
tal forma que el objeto puede
permiten a los usuarios anular operaciones provisionales y/o recuperarse de
ser restaurado a este estado
errores.
después.
Se quiere evitar utilizar una interfaz directa para obtener el estado del
objeto que pudiera violar el principio de encapsulación por exponer detalles
de implementación internos.
Solución
Caretaker
getMemento()
add(Memento)
public createMemento() {
return new Memento(state); Originator
}
state
public setMemento(memento) { createMemento()
state = memento.getState(); setMemento(Memento)
}
Memento
state
getState()
setState()
Memento: clase que almacena el estado interno del objeto Originator. Tiene dos interfaces:
Una interfaz amplia, que permite al Originator acceder a todos los datos necesarios para volver a su estado anterior.
Una interfaz reducida, que sólo permite pasar el objeto Memento a otros objetos, protegiendo así el Memento frente a
accesos que no provengan del Originator. Solo el Originator puede almacenar y recuperar información del Memento – el
Memento es “opaco” a otros objetos.
Caretaker: clase responsable de guardar en lugar seguro los objetos Memento, así como de borrar los Memento que
custodia. Nunca examina sus contenidos ni opera sobre ellos, es decir, sólo conoce la interfaz reducida del Memento.
Implementación
Variaciones
La implementación del patrón Memento es muy dependiente del lenguaje de implementación:
Lo ideal sería que el lenguaje de implementación permitiese dos niveles de protección estática. C++ lo permite haciendo
que Originator sea una clase amiga de Memento, y manteniendo privada la interfaz amplia del Memento y pública la
interfaz reducida.
En otros lenguajes como Java, debido a que el Memento debería ser accesible únicamente desde el Originator, se
puede hacer que el Memento sea una clase interna pública del Originator, declarando todos los métodos privados
para que sólo estén disponibles para el objeto Memento y su clase contenedora Originator, ofreciendo así la encapsulación
apropiada. Dado que el objeto Memento debe ser independiente de una instancia específica de un Originator, la clase
Memento será una clase interna estática.
La cantidad de información que almacena el objeto Memento variará en función de lo que necesite el objeto
Originator para ser capaz de volver a un estado previo. En caso de que los Memento se creen y se devuelvan en una
secuencia predecible, es decir, en un orden concreto, el Memento puede guardar únicamente el cambio con respecto al estado
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 88/117
19/1/2021 Patrones de Diseño
Consecuencias
Ventajas Desventajas
El Memento evita exponer información que sólo debería ser manejada por el El uso del patrón Memento
Originator, pero que sin embargo debe ser guardada fuera de éste. El patrón podría suponer un coste
preserva la encapsulación, lo cual permite: considerable si el Originator
debe copiar grandes
Simplificar el Originator, ya que se evita que éste tenga que responsabilizarse
cantidades de información
de registrar y almacenar todos los estados distintos solicitados por los clientes
para guardarlas en el Memento o
para preservar la encapsulación, ocupándose únicamente de crear los objetos
si los clientes crean y devuelven
Memento y de saber utilizarlos cuando los clientes se lo soliciten.
Mementos a su Originator con
Simplificar los clientes, ya que estos no necesitan saber nada sobre el mucha frecuencia. A menos
funcionamiento interno del Originator, que podría ser potencialmente complejo, que encapsular y restablecer
excepto cómo obtener un Memento y cómo utilizarlo, y evita que los clientes el estado sea poco costoso, el
tengan que notificar a los objetos Originator cuando han acabado. patrón podría no ser
No comprometer la fiabilidad y extensibilidad de la aplicación exponiendo apropiado.
interioridades de los objetos innecesariamente. Una de las principales
clases afectadas por este
coste es Caretaker ya que,
aunque desconoce cuánto
estado hay en un Memento,
es la responsable de
gestionar el ciclo de vida de
estos objetos tras su
creación.
Observer
Problema
Motivación
tener distintos
main()
tipos de Fate
problemas en la provideLifeEventsForMan(Man)
provideLifeEventsForWoman(Woman)
vida, pérdida de un
ser querido o Person
padecimiento de
inTrouble
isInTrouble()
setInTrouble(TroubleReason)
una enfermedad o
getTroubleReason()
loseALovedOne()
haveAFlue()
public notifyKnownPeople() {
wasteAllSavings()
falta de liquidez o
if (this.isNotOrphan()) beBom()
mother.update(); becomOrphan() Partner Mother Boss
if (this.isInRelationship()) startRelationship()
update
que requerir
} isInRelationship()
isEmployed()
attach(Mother)
detach(Mother)
de distintas
detach(Boss)
notifyKnownPeople()
personas de su
entorno, madre o
public update() {
swich (this.person.getTroubleReason()) {
public update() { case SAD:
para sobrellevar
havePreeclampsia() // Partner giving you a hug case WITHOUT_MONEY: }
} // Mother lending you money
}
este valle de
}
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 89/117
19/1/2021 Patrones de Diseño
El acoplamiento de la clase Person (ej. 3) La cohesión de la La granularidad de la clase Person (ej. 22)
depende del número de tipos de personas clase Person no es depende de la cantidad de métodos
de su entorno encargados de prestar adecuada puesto requeridos.
ayuda. que asume varias
Se calcula como la suma de los métodos
responsabilidades
Se calcula como la suma del número de relativos a la responsabilidad de la clase
dispares o que no
tipos de personas de su entorno para gestionar los distintos tipos de
le atañen, como la
encargados de prestar ayuda (ej. Mother, problemas en la vida (ej. isInTrouble,
gestión de los
Partner y Boss, 3). setInTrouble, getTroubleReason,
distintos tipos
loseALovedOne, haveAFlue, wasteAllSavings,
Su resultado es de orden lineal, O(n). personas que le
…, 12) más el producto del número de tipos
prestan ayuda
de personas de su entorno (ej. Mother,
según las
Partner y Boss, 3) por los métodos relativos
circunstancias.
para gestionar la existencia de cada tipo
de persona (ej. attach, detach e is, 3), más el
método para realizar la notificación (ej.
notifyKnowPeople, 1).
Intención
de problemas en la «Subject»
querido o padecimiento
isInTrouble()
setInTrouble(TroubleReason)
getTroubleReason()
public notifyKnownPeople() { loseALovedOne() «Director» «Observer»
falta de liquidez o …,
becomOrphan() provideLifeEventsForWoman(Woman) update()
startRelationship()
endRelationship()
startJob()
personas de su
Woman «ConcreteSubjectA» Boss Mother Partner
Man
update
getPregmant() setPerson(Person) setPerson(Person)
entorno que le
havePreeclampsia() setPerson(Person) update() update()
de lágrimas. }
// Mother lending you money }
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 90/117
19/1/2021 Patrones de Diseño
El acoplamiento de la clase Person (ej. 1) La cohesión de la La granularidad de la clase Person (ej. 15)
depende de un tipo de persona conocida clase Person es depende de la cantidad de métodos
(ej. KnownPeople, 1). adecuada puesto requeridos.
que asume una
Su resultado es de orden constante, O(1). Se calcula como la suma de los métodos
única
relativos a la responsabilidad de la clase
responsabilidad,
para gestionar los distintos tipos de
centrada en la
problemas en la vida (ej. isInTrouble,
gestión de su vida,
setInTrouble, getTroubleReason,
notificando que
loseALovedOne, haveAFlue, wasteAllSavings,
requiere ayuda a la
…, 12) más los métodos relativos para
red de seguridad de
gestionar la existencia de un tipo de
personas de su
persona conocida (ej. attach y detach, 2),
entorno.
más el método para realizar la
notificación (ej. notifyKnowPeople, 1).
Intención Aplicabilidad
La intención de este patrón es Abstracciones que tienen dos aspectos, uno de los cuales depende del otro. La
definir una dependencia uno- encapsulación de estos aspectos en objetos separados permite modificarlos y
a-muchos entre objetos de tal reutilizarlos de manera independiente.
forma que cuando un objeto
Un cambio sobre un objeto requiere cambiar otros y no se conoce cuántos
cambia su estado, todos los
objetos necesitan ser cambiados.
objetos dependientes son
notificados y actualizados Un objeto debería ser capaz de notificar a otros objetos sin hacer asunciones
automáticamente. sobre quiénes son estos objetos. En otras palabras, no se quiere estos objetos
altamente acoplados, para permitir una mayor reusabilidad.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 91/117
19/1/2021 Patrones de Diseño
ConcreteObserverA ConcreteObserverB
Todos los observadores que se
observerStateA observerStateB hayan suscrito previamente
update() update()
son notificados si el
observado sufre un cambio
ConcreteSubjectB ConcreteSubjectA
public update() { public update() { de estado.
subjectStateA subjectStateA observerStateA = subject.getStateA(); observerStateB = subject.getStateB();
getStateA() getStateA() } }
setStateA() setStateA()
Observer: declara la interfaz para actualizar los objetos que deben ser notificados ante cambios en un Subject.
En respuesta a la notificación recibida, cada observador consultará al sujeto observado para sincronizar su estado con el
estado de éste.
Implementa los métodos para responder a las notificaciones recibidas, garantizando la correcta actualización de su
estado, es decir, su actualización de manera consistente con el estado del sujeto al que observa.
Implementación
Variaciones
Hay diversas opciones para implementar la correspondencia entre los sujetos observados y sus observadores:
La forma más simple para que un sujeto realice el seguimiento de los observadores a los que debería notificar sería
almacenar explícitamente las referencias a los observadores. Sin embargo, esto puede ser muy costoso desde el punto
de vista del espacio de almacenamiento cuando hay muchos sujetos observados y pocos observadores.
Otra alternativa es utilizar un array asociativo para búsquedas (por ejemplo, una tabla hash) que mantiene la
correspondencia entre sujetos observados y sus observadores. Este enfoque consigue reducir el coste de almacenamiento a
costa de incrementar el tiempo de acceso, consiguiéndose así un compromiso espacio/tiempo.
En caso de que un observador dependa de más de un sujeto observado, es necesario extender el interfaz de actualización
para permitir al observador conocer qué sujeto observado está enviando la notificación. El sujeto observado puede
simplemente enviarse a sí mismo como parámetro de la operación de actualización permitiendo al observador conocer a qué
sujeto consultar.
Existen dos alternativas para disparar las actualizaciones que mantienen consistentes los estados del sujeto y sus
observadores utilizando el mecanismo de notificación:
Las operaciones que modifican el estado del sujeto se responsabilizan de enviar la notificación a los observadores
después de cambiar el estado del sujeto.
La ventaja de este enfoque es que los clientes no tienen que estar pendientes de indicar al sujeto que envíe las
notificaciones.
La desventaja es que varios cambios consecutivos en el sujeto causarán notificaciones consecutivas a los observadores,
que dispararán sus correspondientes actualizaciones, lo cual puede resultar ineficiente.
La ventaja es que el cliente puede esperar para hacer el envío de éstas hasta que se hayan realizado una serie de
cambios de estado en el sujeto observado, evitando de este modo actualizaciones intermedias innecesarias por parte de
los observadores.
La desventaja es que los clientes tienen una responsabilidad añadida para activar la actualización, lo cual incrementa la
probabilidad de errores, ya que los clientes podrían olvidarse, en un momento dado, de hacer el envío.
En caso de que un sujeto observado sea eliminado, no deben producirse referencias “colgadas” de sus observadores.
Una forma de evitar esto es que el sujeto observado notifique a sus observadores cuando se elimina, de modo que éstos
puedan reinicializar la referencia a él. En general, la alternativa de borrar los observadores no es una opción, ya que otros
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 92/117
19/1/2021 Patrones de Diseño
objetos pueden hacer referencia a ellos, o ellos mismos pueden estar observando a otros sujetos.
Es importante asegurar que el estado del sujeto observado es consistente consigo mismo antes de enviar las
notificaciones a los observadores, ya que éstos consultarán al sujeto por su estado actual durante el proceso de actualizar su
propio estado.
Esta regla de auto-consistencia se puede violar involuntariamente cuando subclases del sujeto observado llaman a métodos
heredados. Para evitarlo, se pueden utilizar métodos plantilla cuya última operación sea el envío de notificaciones, y en la
que las subclases únicamente redefinirán las operaciones previas al envío según sus responsabilidades.
Habitualmente, el sujeto observado transmite información adicional acerca del cambio experimentado como un
argumento de la actualización. La cantidad de información puede variar ampliamente. Existen diversos enfoques para esta
transmisión entre Subject-Observer:
En un extremo, se encuentra el modelo de inserción (push), en el cual el sujeto observado envía información detallada a
los observadores sobre el cambio, lo quieran o no. El modelo de inserción asume que los sujetos saben algo acerca de las
necesidades de sus observadores.
En el otro extremo, se encuentra el modelo de extracción (pull), en el cual el sujeto observado envía únicamente la
notificación mínima, y los observadores consultarán por los detalles de forma explícita posteriormente. El modelo de
extracción hace hincapié en la ignorancia del sujeto sobre sus observadores.
La complejidad de la relación de dependencia entre los sujetos y los observadores puede requerir la utilización de un
objeto que encapsule la semántica de las actualizaciones, denominado ChangeManager. Su objetivo es reducir al
mínimo el trabajo necesario para hacer que los observadores reflejen un cambio en sus observados. Por ejemplo, si una
operación involucra cambios en varios sujetos observados interdependientes, puede que tenga que asegurarse de que sus
observadores son notificados después de que todos los sujetos se han modificado para evitar la notificación a los observadores
más de una vez. ChangeManager tiene tres responsabilidades:
Relacionar un sujeto observado y sus observadores, proporcionando una interfaz para mantener esta relación. Se
elimina así la necesidad de que los sujetos observados mantengan las referencias a sus observadores y viceversa.
Se puede mejorar la eficiencia en la actualización mediante la ampliación de interfaz de registro del sujeto observado
permitiendo que los observadores se registren sólo para eventos específicos de su interés en lugar de hacer un registro
genérico que incluiría cualquier evento. Cuando tal evento se produce, el sujeto observado informa sólo a aquellos
observadores que hayan registrado interés en ese evento. Una forma de apoyar esto es utilizar la noción de aspectos en los
objetos sujeto.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 93/117
19/1/2021 Patrones de Diseño
Relacionar Estructuras del Tiempo de Acoplamiento Añadir funcionalidad mediante herencia Principio
Compilación y de Ejecución Abierto/Cerrado
State
Problema
Motivación
Una persona
Scenario
realiza diversas
actividades a lo
main()
largo del día,
comer o bailar o
trabajar o …, pero
dependiendo de
public eat() {
su estado de
if (this.mood == AvailableMood.HAPPY) {
ánimo, feliz o triste this.eatHappy();
o …, las realizará } else if (this.mood == AvailableMood.SAD) {
con distintos this.eatSad();
algoritmos. }
}
Person
public dance() {
mood if(this.mood == AvailableMood.HAPPY) {
eat() this.danceHappy();
dance() } else if (this.nood == AvailableMood.SAD) {
work() this.danceSad();
eatHappy() tis.mood = AvailableMood.HAPPY;
eatSad()
}
danceHappy()
danceSad() }
workHappy()
workSad() public work() {
if (this.mood == AvailableMood.HAPPY) {
tis.workHappy();
this.mood == AvaailableMood.SAD;
} else if (this.mood == AvailableMood.SAD) {
this.workSad();
}
}
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 94/117
19/1/2021 Patrones de Diseño
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 95/117
19/1/2021 Patrones de Diseño
La
Scenario
responsabilidad
de la persona
main()
incluye la
delegación de la
realización de la
actividad en
public eat() {
diferentes estados
this.mood.eat();
de ánimo, que se }
responsabilizan
«Context»
por separado del Person public dance() {
algoritmo a this.mood.dance();
mood this.mood = new Happy();
seguir para
eat() }
realizar cada dance()
actividad work() public work() {
dependiendo del this.mood.work();
this.mood = new Sad();
estado de ánimo.
}
De esta manera,
ninguna clase será
compleja y se
evitará la tendencia
a crecer. «State»
Mood
eat()
dance()
work()
«ConcreteStateA» «ConcreteStateB»
Happy Sad
eat() eat()
dance() dance()
work() work()
Intención Aplicabilidad
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 96/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
El patrón State pone cada rama de la condición en una clase aparte, lo cual
permite tratar al estado del objeto como un objeto de pleno derecho que puede
variar de manera independiente de otros objetos.
Solución
State
handle()
ConcreteStateA ConcreteStateB
handle() handle()
State: declara una interfaz para encapsular el comportamiento asociado con un determinado estado del objeto Context.
ConcreteState: clase derivada de State que implementa un comportamiento específico asociado con un estado de Context.
Implementación
Variaciones
El patrón State no especifica qué participante define los criterios para las transiciones entre estados. Se puede optar
entre diversas opciones:
No obstante, es generalmente más flexible y conveniente que sean las propias subclases ConcreteState quienes
especifiquen su estado sucesor y cuándo llevar a cabo la transición. Esto requiere añadir una interfaz a Context que
permita a los objetos State asignar explícitamente el estado actual del contexto.
Descentralizar de esta forma la lógica de la transición facilita modificar o extender dicha lógica definiendo nuevas
subclases de State.
Una desventaja de la descentralización es que una subclase de State conocerá al menos a otra, lo que introduce
dependencias de implementación entre subclases.
También existe otra alternativa basada en tablas de correspondencia. Para cada estado, una tabla hace corresponder
cada posible entrada con un estado sucesor. Este enfoque convierte código condicional (y funciones virtuales, en el caso
del patrón State) en una tabla de búsqueda. La principal ventaja de las tablas es su regularidad: se pueden cambiar los
criterios de transición modificando datos en vez del código del programa. No obstante, este enfoque presenta algunos
inconvenientes:
Es más difícil realizar algún tipo de procesamiento arbitrario con cada transición. Para ello es necesario
complementar esta técnica con algún otro mecanismo.
Instanciación diferida, es decir, creación de los objetos cuando se necesitan (y destrucción cuando dejan de ser
necesarios).
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 97/117
19/1/2021 Patrones de Diseño
Este enfoque es preferible cuando no se conocen los estados en tiempo de ejecución y los contextos cambian de
estado con poca frecuencia. Se evita así crear objetos que no se usarán nunca, lo que puede ser importante si los
objetos State guardan una gran cantidad de información.
Este enfoque es más adecuado cuando los cambios tienen lugar rápidamente, en cuyo caso interesa evitar
destruir los objetos State, ya que pueden volver a necesitarse de nuevo en breve. Los costes de creación se pagan al
principio y no existen costes de destrucción. No obstante, esta alternativa tiene el inconveniente de que el objeto Context
debe guardar referencias a todos los estados en los que pueda entrar.
Consecuencias
Ventajas Desventajas
Sitúa en un objeto todo el comportamiento asociado con un determinado El patrón aumenta el número
estado. Como todo el código dependiente del estado reside en una subclase de State, de objetos de una aplicación.
pueden añadirse fácilmente nuevos estados y transiciones definiendo nuevas
A veces se puede reducir este
subclases.
coste si los objetos State no
Esto incrementa el número de clases y es menos compacto que una única tienen variables, es decir, si el
clase, pero se evita que la lógica que determina las transiciones entre estados estado que representan está
resida en grandes sentencias if o switch monolíticas, siendo en su lugar repartida totalmente representado por
entre las subclases de State. su tipo, pudiendo así varios
contextos compartir un
Al encapsular cada transición y acción en una clase, estamos elevando la idea de
mismo objeto State. Cuando
un estado de ejecución a objetos de estado en toda regla. Esto impone una
se comparten los estados de
estructura al código y hace que su intención sea más clara.
este modo, son en esencia
Introducir objetos separados para los diferentes estados hace que las transiciones objetos FlyWeight que no
sean más explícitas. Además, los objetos State pueden proteger a Context frente a tienen estado intrínseco,
estados internos inconsistentes, ya que las transiciones entre estados son atómicas sino solo comportamiento.
para él puesto que tienen lugar cambiando una única variable (la variable de tipo
State del objeto Context).
Strategy
Problema
Motivación
actividades a lo
largo de su vida,
public flirt() { public flirt() {
flirtear o hacer // Trying to flirt
Person
// Trying to make frienship
if (this.approach == Approach.SHARED_FRIEND) { if (this.approach == Approach.SHARED_FRIEND) {
amistades o …, this.approachWithSharedFriendApproach();
} else if (this.approach == Approach.SHARED_HOBBY) {
setApproach()
this.approachWithSharedFriendApproach();
} else if (this.approach == Approach.SHARED_HOBBY) {
flirt()
pero tras realizar this.approachWithSharedHobbyApproach();
} else if (this.approach == Approach.STRAIGHTFORWARD)
makeFriendship()
apporoachWithSharedFriendApproach()
this.approachWithSharedHobbyApproach();
} else if (this.approach == Approach.STRAIGHTFORWARD)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 98/117
19/1/2021 Patrones de Diseño
Intención
Si la
Scenario
responsabilidad
de persona main()
incluye
únicamente la
delegación de la
«Director»
realización de la SentimentalCounselor
actividad y otros,
teachSharedFriendApproach(Person)
consejero teachSharedHobbyApproach(Person)
teachSharedForwardApproach(Person)
sentimental y
estrategias de
aproximación, se
responsabilizan
public flirt() { «Context»
por separado del // Trying to flirt Person
análisis del this.approach.approach();
set(Approach)
// Inviting to dinner
contexto y del }
flirt()
makeFriendship()
algoritmo a
seguir para
realizar cada
actividad, ninguna public makeFrienship() {
«Strategy»
clase será compleja // Trying to make frienship
Approach
this.approach.approach();
y se evitará la // inviting to match
approach()
tendencia a crecer. }
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 99/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Muchas clases relacionadas difieren en su comportamiento. Las estrategias
definir una familia de permiten configurar una clase con un determinado comportamiento de entre
algoritmos, encapsulando muchos posibles en tiempo de ejecución.
cada uno y haciéndolos
Se necesitan distintas variantes de un algoritmo, por ejemplo, con distintas
intercambiables, permitiendo
soluciones de compromiso entre tiempo y espacio. Pueden usarse estrategias
al algoritmo variar de manera
cuando estas variantes se implementan como una jerarquía de clases de algoritmos.
independiente del cliente que
lo utilice. Un algoritmo usa datos que los clientes no deberían conocer. El patrón Strategy
permite evitar exponer estructuras de datos complejas y dependientes del
algoritmo.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 100/117
19/1/2021 Patrones de Diseño
Director
Context
contextInterface()
Strategy
AlgorithmInterface()
ConcreteStrategyB ConcreteStrategyA
AlgorithmInterface() AlgorithmInterface()
Context: clase que utiliza las diferentes estrategias para una determinada tarea. Se configura con un objeto
ConcreteStrategy y mantiene una referencia al objeto Strategy que está utilizando en cada momento.
Puede definir una interfaz que permita a una ConcreteStrategy acceder a sus datos.
Implementación
Variaciones
Las interfaces Strategy y Context deben permitir a una ConcreteStrategy acceder de manera eficiente a cualquier dato que
ésta necesite del contexto, y viceversa. Existen diversas opciones:
Un enfoque es que Context pase los datos como parámetros a las operaciones de Strategy, es decir, llevar los datos a la
estrategia. Esto mantiene a Strategy y Context desacoplados. El principal inconveniente de esta alternativa es que
Context podría pasar datos a la Strategy que ésta no necesita.
Otra técnica es que Context se pase a sí mismo como argumento, y que Strategy le pida los datos explícitamente al
contexto. Como alternativa, la estrategia puede guardar una referencia a su contexto, eliminando así la necesidad de pasar
nada. El principal inconveniente de este enfoque es que Context debe definir una interfaz más elaborada para sus datos, lo
que acopla más estrechamente a Strategy y Context.
Se pueden utilizar las plantillas para configurar una clase con una estrategia. Esta técnica solo es aplicable si se puede
seleccionar la estrategia en tiempo de compilación y no hay que cambiarla en tiempo de ejecución. En este caso, la clase
Context se define en una clase plantilla que tiene como parámetro una clase Strategy.
Se puede proporcionar en Context un comportamiento predeterminado y hacer opcionales los objetos Strategy.
Context comprueba si tiene un objeto Strategy antes de acceder a él y, en caso de que exista, lo usa normalmente. Pero, en
caso de que no tenga sentido tener un objeto Strategy y éste no exista, Context realiza el comportamiento
predeterminado. La ventaja de este enfoque es que los clientes solo tienen que tratar con los objetos Strategy cuando no les
sirva el comportamiento por defecto.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 101/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
Las jerarquías de clases Strategy definen una familia de algoritmos o El patrón tiene el
comportamientos para ser reutilizados por los contextos. La herencia puede inconveniente potencial de
ayudar a sacar factor común de la funcionalidad de estos algoritmos. que un cliente debe
comprender cómo difieren las
La herencia ofrece otra forma de permitir una variedad de algoritmos o
distintas ConcreteStrategy
comportamientos. Se puede heredar de Context para proporcionar diferentes
antes de seleccionar la
comportamientos, pero esto liga el comportamiento a Context, mezclando la
adecuada. Los clientes pueden
implementación del algoritmo con la de Context. Esto dificulta su comprensión,
estar expuestos a cuestiones de
mantenimiento y extensión e impide la modificación del algoritmo
implantación. Por tanto, debería
dinámicamente. El resultado será una gran cantidad de clases relacionadas cuya
usarse solo cuando la variación
única diferencia es el algoritmo o comportamiento que utilizan. Encapsular el
de comportamiento sea
algoritmo en clases Strategy separadas permite variar el algoritmo
relevante a los clientes.
independientemente de su contexto, haciendo este más fácil de cambiar,
comprender y extender. La interfaz de Strategy es
compartida por todas las clases
ConcreteStrategy, ya sea el
El patrón ofrece una alternativa a las sentencias condicionales para algoritmo que implementan
seleccionar el comportamiento deseado, ya que, en su ausencia, cuando se trivial o complejo. Por tanto, es
juntan muchos comportamientos en una clase es difícil no recurrir a éstas para probable que algunos objetos
seleccionar el comportamiento correcto. ConcreteStrategy no usen
toda la información que
Las estrategias permiten proporcionar distintas implementaciones del mismo
reciben a través de dicha
comportamiento. El cliente puede elegir entre estrategias con diferentes soluciones
interfaz; pudiendo darse el
de compromiso entre tiempo y espacio.
caso incluso de que las
estrategias concretas simples
no utilicen ninguna en
absoluto. Esto implica que
habrá ocasiones en las que el
contexto cree e inicialice
parámetros que nunca se usan.
Si esto puede ser un problema,
necesitaremos un acoplamiento
más fuerte entre Strategy y
Context.
Template Method
Problema
Motivación
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 102/117
19/1/2021 Patrones de Diseño
Un profesor se
Scenario
responsabiliza de
enseñar con el
main()
mismo algoritmo,
presentarse,
presentar el curso,
explicar los
contenidos, Student
responder las
attendCourse(Professor)
dudas, evaluar y
despedir el curso,
pero dependiendo
de la localización,
clase o campo o …, public teach() {
this.introduceYourself();
algunos pasos del
Professor this.introduceCourse();
algoritmo serán if (professorLocation == Location.CLASSROOM.ordinal())
variables ya que teach() this.explainSubjectInClassRoom();
los realizará de explainSubjectinClassRoom() else ifprofessorLocation == Location.FIELD.ordinal())
manera distinta,
explainSubjectinField() this.expandinSubjectInField();
assessInClassRoom() this.answerDoubts();
bien con distintos assessInField()
if (professorLocation == Location.CLASSROOM.ordinal())
recursos didácticos introduceYourself()
introduceCource()
this.assessInClassRoom();
(proyector o pizarra answerDoubts() else if (professorLocation == Location.FIELD.ordinal())
o …, Moodle o folio concludCourse() this.assessInField();
this.concludeCource();
o …) o con distinto
}
nivel de detalle
(exhaustivo o
superficial o …) , o Esto complica la comprensión de su comportamiento y tiende a crecer a medida que
… surgen nuevas opciones para los pasos variables.
Código de Contraejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/TemplateMethod/templateMethodWrong)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 103/117
19/1/2021 Patrones de Diseño
Intención
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 104/117
19/1/2021 Patrones de Diseño
Si la
Scenario
responsabilidad
de profesor
main()
incluye
únicamente la
solicitud de
realizar los pasos
«Director»
variables y otros,
Student
profesores
concretos, se attendCourse(Professor)
responsabilizan
por separado de
cómo se realizan
los pasos «AbstractClass»
public teach() {
variables, ninguna Professor
this.introduceYourself();
clase será compleja this.introduceCourse();
teach()
y se evitará la explainSubject() this.explainSubject();
tendencia a crecer. assess() this.answerDoubts();
introduceYourself() this.assess();
introduceCource() this.concludeCource();
answerDoubts()
}
concludCourse()
«ConcreteClassA» «ConcreteClassB»
ProfessorInClassRoom ProfessorInField
explainSubject() explainSubject()
assess() assess()
Código de Ejemplo
(https://github.com/USantaTecla-disenyo/designPatterns/tree/master/src/main/java/usantatecla/TemplateMethod/templateMethodFine)
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 105/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Implementar las partes invariantes de un algoritmo, permitiendo que sean las
definir el esqueleto de un subclases quienes implementen el comportamiento que puede variar.
algoritmo en una operación,
Factorizar un comportamiento repetido de varias subclases para ubicarlo en una
difiriendo algunos pasos a las
clase común evitando así código duplicado.
subclases para que éstas
puedan redefinirlos sin Controlar la extensión de subclases en puntos específicos mediante la
cambiar la estructura. definición de un método plantilla que llame a operaciones vacías (conocidas
como operaciones de enganche), que puedan ser redefinidas por las subclases,
restringiendo así las extensiones de las mismas a estos puntos de enganche.
Solución
public templateMethod() {
AbstractClass ...
this.primitiveOperation1();
templateeMethod() ...
primitiveOperation1() this.primitiveOperation2();
primitiveOperation2() ...
}
ConcreteClassA ConcreteClassB
primitiveOperation1() primitiveOperation1()
primitiveOperation2() primitiveOperation2()
Se pueden identificar las operaciones que deberían ser redefinidas añadiendo un sufijo a su nombre, por ejemplo “do-”.
Se pueden declarar con visibilidad protegida para garantizar que solo puedan ser llamadas por el método plantilla.
Se debe minimizar el número de operaciones primitivas que una subclase debe redefinir para dar cuerpo al algoritmo.
Implementa un método plantilla que define el esqueleto de un algoritmo. Este método llama a las operaciones primitivas
abstractas, así como a operaciones definidas en AbstractClass u otras clases.
Se puede declarar como final para evitar que pueda ser redefinido.
ConcreteClass: clase derivada de AbstractClass que implementa las operaciones primitivas abstractas para realizar los
pasos del algoritmo específicos de las subclases.
Implementación
Variaciones
Las dos principales variantes del patrón Template Method son:
La clase AbstractClass es una clase abstracta y no proporciona una implementación para las operaciones primitivas
que declara. Requiere que las subclases definan una implementación porque no hay ningún comportamiento
predeterminado razonable.
La clase AbstractClass es una clase abstracta (menos común) o concreta y proporciona una implementación
predeterminada para las operaciones primitivas que declara. Estas operaciones se denominan operaciones de
enganche, y permiten controlar la extensión de subclases en puntos específicos. Una operación de enganche normalmente
no hace nada por omisión, por lo que es fundamental identificarlas convenientemente para que no sean obviadas.
Consecuencias
Ventajas Desventajas
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 106/117
19/1/2021 Patrones de Diseño
Ventajas Desventajas
Los métodos plantilla son una técnica fundamental de reutilización de código. Un número elevado de
operaciones primitivas que
Los métodos plantilla llevan a una estructura de control invertido, es decir, una
requieran ser redefinidas puede
clase padre llama a las operaciones de una subclase y no al revés. Los métodos
resultar tedioso para los clientes.
plantilla llaman a los siguientes tipos de operaciones primitivas:
Un objetivo importante para
Operaciones abstractas que deben ser obligatoriamente redefinidas por las diseñar métodos plantilla es
subclases. minimizar el número de
operaciones primitivas que una
subclase debe redefinir para dar
Operaciones concretas, ya sea de la ConcreteClass, de la AbstractClass, o de las cuerpo al algoritmo.
clases cliente.
Visitor
Problema
Motivación
Un paciente
cuando tiene un
accidente se
responsabiliza de
realizar distintas
actividades
médicas, evaluar
los daños,
diagnosticarse,
operarse, … sobre
las distintas
partes del cuerpo,
cabeza, tronco,
extremidad, …
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 107/117
19/1/2021 Patrones de Diseño
Scenario
main()
Hospital
treatPatient(Patient)
Patient
add(BodyPart)
evaluate()
diagnose()
operate()
BodyPart
evaluate()
diagnose()
operate()
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 108/117
19/1/2021 Patrones de Diseño
Intención
Si la
Scenario
responsabilidad
main()
del paciente
incluye
únicamente la
aceptación de la «Director»
Hospital
visita sobre las
treatPatient(Patient)
distintas partes
del cuerpo por el
personal del
«Visitor»
hospital y otros, el Staff
«ObjectStructure»
Patient
personal del
visitHead(Head)
hospital, se visitTrunk(Trunk)
add(BodyPart)
accept(Staff)
visitLimb(Limb)
responsabilizan
por separado de
cómo se realizan
«ConcreteVisitirB» «ConcreteVisitirC» «ConcreteVisitirA»
las distintas Doctor Surgeon TriageNurse «Element»
actividades BodyPart
visitHead(Head) visitHead(Head) visitHead(Head)
médicas sobre visitTrunk(Trunk) visitTrunk(Trunk) visitTrunk(Trunk) accept(Staff)
visitLimb(Limb) visitLimb(Limb) visitLimb(Limb)
cada parte del
cuerpo del
paciente, ninguna
«ConcreteElementA» «ConcreteElementB» «ConcreteElementC»
clase será compleja Head Trunk Limb
y se evitará la
accept(Staff) accept(Staff) accept(Staff)
tendencia a crecer.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 109/117
19/1/2021 Patrones de Diseño
Intención Aplicabilidad
La intención de este patrón es Una estructura de objetos contiene muchas clases de objetos con diferentes
representar una operación a interfaces y se quiere realizar operaciones sobre esos elementos que
realizar sobre los elementos dependen de la clase concreta.
de una estructura de objetos,
Se necesita realizar muchas operaciones distintas y no relacionadas sobre
permitiendo definir nuevas
objetos de una estructura de objetos y se quiere evitar “contaminar” sus clases
operaciones sin cambiar las
con dichas operaciones. El patrón Visitor permite mantener juntas operaciones
clases los de elementos sobre
relacionadas definiéndolas en una clase. Cuando la estructura de objetos es
los que opera.
compartida por varias aplicaciones, el patrón Visitor permite poner operaciones
sólo en aquellas aplicaciones que las necesitan.
Las clases que definen la estructura de objetos rara vez cambian, pero muchas
veces se quiere definir nuevas operaciones sobre la estructura. Cambiar las
clases de la estructura de objetos requiere redefinir la interfaz para todos los
visitantes, lo que es potencialmente costoso. Si las clases de la estructura cambian
con frecuencia, probablemente sea mejor definir las operaciones en las propias
clases.
Solución
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 110/117
19/1/2021 Patrones de Diseño
ConcreteVisitirA ConcreteVisitirB
Element
visitConcreteElementA(ConcreteElementA) visitConcreteElementA(ConcreteElementA)
accept(Visitor)
visitConcreteElementB(ConcreteElementB) visitConcreteElementB(ConcreteElementB)
ConcreteElementA ConcreteElementB
accept(Visitor) accept(Visitor)
operationA() operationA()
ConcreteVisitor: clase derivada de Visitor que implementa las operaciones visit definidas en la interfaz. Cada clase
ConcreteVisitor representa una operación específica del sistema, y cada operación visit implementa el comportamiento
específico del visitante para la clase ConcreteElement correspondiente. ConcreteVisitor proporciona el contexto para el
algoritmo y guarda su estado local. Muchas veces este estado acumula resultados durante el recorrido de la estructura.
Element: declara una clase abstracta o interfaz que define una operación accept que recibe un Visitor como argumento. La
clase Element representa los objetos sobre los que actúa Visitor.
ConcreteElement: clase derivada de Element que implementa la operación accept definida en la interfaz invocando al
método visit apropiado definido en Visitor. Cada clase ConcreteElement representa una entidad específica del sistema.
Puede proporcionar una interfaz de alto nivel para permitir al visitante visitar a sus elementos.
Puede ser una clase Composite o una colección, como una lista o un conjunto.
Implementación
Variaciones
El patrón Visitor permite añadir operaciones a clases sin modificar éstas. Esto se logra mediante la técnica de doble-
despacho, llamada así porque la operación que se ejecuta depende del tipo de solicitud y de los tipos de dos receptores.
Accept es una operación de doble-despacho, puesto que su significado depende de dos tipos: el del Visitor y el del
Element. El doble-despacho permite a los ConcreteVisitor solicitar diferentes operaciones en cada clase ConcreteElement.
Esta es la clave del patrón Visitor: la operación que se ejecuta depende tanto del tipo de Visitor como del tipo de
Element visitado. En vez de enlazar operaciones estáticamente en la interfaz de Element, se pueden fusionar las
operaciones en un Visitor y usar accept para hacer el enlace en tiempo de ejecución. Extender la interfaz de Element
consiste en definir una nueva subclase de Visitor en vez de muchas nuevas subclases de Element.
El algoritmo de recorrido que un visitante debe utilizar para visitar cada elemento de la estructura de objetos puede
ser definido en la estructura de objetos, en un objeto iterador aparte o en el visitante:
En muchas ocasiones es la propia estructura de objetos la responsable de la iteración. Una colección simplemente
iterará sobre sus elementos, llamando a la operación accept de cada elemento. Un objeto Composite generalmente se
recorrerá a sí mismo haciendo que cada operación accept recorra los hijos del elemento y llame a accept sobre cada uno de
ellos recursivamente.
Otra solución es utilizar un iterador para visitar los elementos, bien sea externo o interno, dependiendo de la
disponibilidad y la eficiencia.
Puesto que los iteradores internos son implementados por la estructura de objetos, usar un iterador interno es muy
similar a que sea la estructura de objetos la responsable de la iteración. La principal diferencia estriba en que un iterador
interno no provocará un doble-despacho, sino que llamará a una operación del visitante con un elemento como
argumento, frente a llamar a una operación del elemento con el visitante como argumento. Pero resulta sencillo usar el
patrón Visitor con un iterador interno si la operación del visitante simplemente llama a la operación del elemento sin
recursividad.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 111/117
19/1/2021 Patrones de Diseño
Otra alternativa consiste en ubicar el algoritmo de recorrido en el visitante, si bien en ese caso se duplica el código del
recorrido en cada ConcreteVisitor para cada agregado ConcreteElement. La principal razón para seguir este enfoque es
poder implementar un recorrido especialmente complejo que dependa de los resultados de las operaciones realizadas sobre
la estructura de objetos.
Consecuencias
Ventajas Desventajas
Los visitantes facilitan añadir nuevas operaciones que dependen de los El patrón Visitor hace que sea
componentes de objetos complejos. Se puede definir una nueva operación sobre complicado añadir nuevas
una estructura simplemente añadiendo un nuevo visitante. Si, por el contrario, subclases ConcreteElement, ya
extendiésemos la funcionalidad sobre muchas clases, habría que cambiar cada clase que cada nueva clase
para definir una nueva operación. ConcreteElement da lugar a una
nueva operación abstracta de
El comportamiento similar no está desperdigado por las clases que definen la
Visitor y a su correspondiente
estructura de objetos; sino que está localizado en un visitante. Las partes de
implementación en cada clase
comportamiento no relacionadas se dividen en sus propias subclases del visitante.
ConcreteVisitor. A veces se
Esto simplifica tanto las clases que definen los elementos como los algoritmos
puede proporcionar en Visitor
definidos por los visitantes. Cualquier estructura de datos específica de un algoritmo
una implementación
puede estar oculta en el visitante.
predeterminada que puede
Los visitantes pueden acumular estado a medida que van visitando cada ser heredada por la mayoría
elemento de la estructura de objetos. Sin un visitante, este estado se pasaría como de los ConcreteVisitor, pero
argumentos extra a las operaciones que realizan el recorrido, o quizá como esto representa una excepción
variables globales. más que una regla.
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 112/117
19/1/2021 Patrones de Diseño
Especificar interfaces de objetos Abstracción Incapacidad para modificar las clases Principio
convenientemente Abierto/Cerrado
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 113/117
19/1/2021 Patrones de Diseño
Relaciones
chainofResponsability Mediator Adapter Proxy
Singleton templateMethod
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 114/117
19/1/2021 Patrones de Diseño
Aplicación
Selección Uso
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 115/117
19/1/2021 Patrones de Diseño
Bibliografía
Obra, Autor y Edición Portada Obra, Autor y Edición Portada
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 116/117
19/1/2021 Patrones de Diseño
Ponente
Luis Fernández Muñoz Doctor en Inteligencia Artificial por
la UPM
Formador/Consultor
Ingeniero en Informática por la
Linkedin (https://es.linkedin.com/in/luisfernandezmunyoz)
UMA
Version 0.0.1
Last updated 2020-12-10 10:12:37 +0100
file:///C:/USantaTecla/itinerario/x-publicaciones/USantaTecla/2-disenyo/4-patronesDisenyo/index.html 117/117