Design Patterns Es
Design Patterns Es
Design Patterns Es
Sumérggete en lo
loss
PATR
TRONE
ONESS
DE
DI
DISEÑO
SEÑO
v2023-1.21
Índice de contenido
Índice de contenido............................................................................................... 4
Cómo leer este libro.............................................................................................. 6
FUNDAMENTOS DE LA POO .................................................................................. 7
Conceptos básicos de POO ............................................................... 8
Los pilares de la POO ...................................................................... 13
Relaciones entre objetos................................................................ 21
INTRODUCCIÓN A LOS PATRONES DE DISEÑO............................................... 27
¿Qué es un patrón de diseño?...................................................... 28
¿Por qué debería aprender sobre patrones? ........................... 33
PRINCIPIOS DE DISEÑO DE SOFTWARE .......................................................... 34
Características del buen diseño................................................... 35
Principios del diseño..................................................................................... 39
§ Encapsula lo que varía ................................................................ 40
§ Programa a una interfaz, no a una implementación ........ 45
§ Favorece la composición sobre la herencia......................... 50
Principios SOLID ............................................................................................ 54
§ S: Principio de responsabilidad única.................................... 55
§ O: Principio de abierto/cerrado................................................ 57
§ L: Principio de sustitución de Liskov...................................... 61
§ I: Principio de segregación de la interfaz ............................. 68
§ D: Principio de inversión de la dependencia....................... 71
[email protected] (#160493)
5 Índice de contenido #160493
[email protected] (#160493)
6 Cómo leer este libro #160493
Los patrones de diseño son universales. Por ello, todos los eje-
mplos de código de este libro están escritos en un pseudocódi-
go que no restringe el material a un lenguaje de programación
particular.
[email protected] (#160493)
#160493
FUNDAMENTOS
DE LA POO
[email protected] (#160493)
8 Fundamentos de la POO / Conceptos básicos de POO #160493
Objetos, clases
¿Te gustan los gatos? Espero que sí, porque voy a intentar
explicar los conceptos de POO utilizando varios ejemplos
con gatos.
[email protected] (#160493)
9 Fundamentos de la POO / Conceptos básicos de POO #160493
[email protected] (#160493)
10 Fundamentos de la POO / Conceptos básicos de POO #160493
Jerarquías de clase
Todo va muy bien mientras hablamos de una sola clase. Natu-
ralmente, un programa real contiene más de una clase. Algu-
nas de esas clases pueden estar organizadas en jerarquías de
clase. Veamos lo que esto significa.
[email protected] (#160493)
11 Fundamentos de la POO / Conceptos básicos de POO #160493
[email protected] (#160493)
12 Fundamentos de la POO / Conceptos básicos de POO #160493
[email protected] (#160493)
13 Fundamentos de la POO / Los pilares de la POO #160493
Abstracción
La mayoría de las veces, cuando creas un programa con POO,
das forma a los objetos del programa con base a objetos del
mundo real. Sin embargo, los objetos del programa no repre-
sentan a los originales con una precisión del 100 % (y rara vez
es necesario que lo hagan). En su lugar, tus objetos tan solo co-
pian atributos y comportamientos de objetos reales en un co-
ntexto específico, ignorando el resto.
[email protected] (#160493)
14 Fundamentos de la POO / Los pilares de la POO #160493
Encapsulación
Para arrancar el motor de un auto, tan solo debes girar una
llave o pulsar un botón. No necesitas conectar cables bajo el
capó, rotar el cigüeñal y los cilindros, e iniciar el ciclo de po-
[email protected] (#160493)
15 Fundamentos de la POO / Los pilares de la POO #160493
jetos. Ésta es una de las razones por las que las interfaces sólo
se interesan por los comportamientos de los objetos, y tam-
bién el motivo por el que no puedes declarar un campo en una
interfaz.
[email protected] (#160493)
16 Fundamentos de la POO / Los pilares de la POO #160493
[email protected] (#160493)
17 Fundamentos de la POO / Los pilares de la POO #160493
Herencia
La herencia es la capacidad de crear nuevas clases sobre otras
existentes. La principal ventaja de la herencia es la reutiliza-
ción de código. Si quieres crear una clase ligeramente diferen-
te a una ya existente, no hay necesidad de duplicar el código.
En su lugar, extiendes la clase existente y colocas la funciona-
lidad adicional dentro de una subclase resultante que hereda
los campos y métodos de la superclase.
[email protected] (#160493)
18 Fundamentos de la POO / Los pilares de la POO #160493
Polimorfismo
Veamos algunos ejemplos con animales. La mayoría de los
Animal puede emitir sonidos. Podemos anticipar que todas
[email protected] (#160493)
19 Fundamentos de la POO / Los pilares de la POO #160493
[email protected] (#160493)
20 Fundamentos de la POO / Los pilares de la POO #160493
1 bag = [new
new Cat(), new Dog()];
2
3 foreach (Animal a : bag)
4 a.makeSound()
5
6 // ¡Miau!
7 // ¡Guau!
[email protected] (#160493)
21 Fundamentos de la POO / Relaciones entre objetos #160493
Dependencia
[email protected] (#160493)
22 Fundamentos de la POO / Relaciones entre objetos #160493
Asociación
[email protected] (#160493)
23 Fundamentos de la POO / Relaciones entre objetos #160493
1 class Professor is
2 field Student student
3 // ...
4 method teach(Course c) is
5 // ...
6 this
this.student.remember(c.getKnowledge())
[email protected] (#160493)
24 Fundamentos de la POO / Relaciones entre objetos #160493
Agregación
[email protected] (#160493)
25 Fundamentos de la POO / Relaciones entre objetos #160493
Composición
La visión global
Ahora que conocemos todos los tipos de relaciones entre ob-
jetos, veamos cómo se conectan entre sí. Esperemos que esto
te ayude a responder preguntas como: “¿cuál es la diferencia
entre agregación y composición?” o “¿la herencia es un tipo de
dependencia?”.
[email protected] (#160493)
26 Fundamentos de la POO / Relaciones entre objetos #160493
[email protected] (#160493)
#160493
INTRODUCCIÓN
A LOS PATRONES
[email protected] (#160493)
28 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #160493
[email protected] (#160493)
29 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #160493
[email protected] (#160493)
30 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #160493
Los patrones más universales y de más alto nivel son los patro-
nes de arquitectura. Los desarrolladores pueden implementar
estos patrones prácticamente en cualquier lenguaje. Al contra-
rio que otros patrones, pueden utilizarse para diseñar la arqui-
tectura de una aplicación completa.
[email protected] (#160493)
31 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #160493
[email protected] (#160493)
32 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #160493
[email protected] (#160493)
33 #160493
Introducción a los patrones de diseño / ¿Por qué debería aprender sobre patrones?
[email protected] (#160493)
#160493
PRINCIPIOS
DE DISEÑO
DE SOFTWARE
[email protected] (#160493)
35 Principios de diseño de software / Características del buen diseño #160493
Reutilización de código
Costos y tiempo son dos de los parámetros más valiosos a la
hora de desarrollar cualquier producto de software. Dedicar
menos tiempo al desarrollo se traduce en entrar en el mercado
antes que la competencia. Unos costos más bajos en el desa-
rrollo significa que habrá más dinero disponible para marketi-
ng y un alcance más amplio a clientes potenciales.
[email protected] (#160493)
36 Principios de diseño de software / Reutilización de código #160493
1
Aquí tienes un apunte de sabiduría de Erich Gamma , uno
de los padres fundadores de los patrones de diseño, sobre el
papel que estos juegan en la reutilización de código:
[email protected] (#160493)
37 Principios de diseño de software / Extensibilidad #160493
„
zar ideas y conceptos de diseño con independencia del código
concreto.
Extensibilidad
El cambio es lo único constante en la vida de un programador.
[email protected] (#160493)
38 Principios de diseño de software / Extensibilidad #160493
[email protected] (#160493)
39 Principios del diseño #160493
[email protected] (#160493)
40 Principios del diseño / Encapsula lo que varía #160493
Del mismo modo, puedes aislar las partes del programa que
varían, en módulos independientes, protegiendo el resto del
código frente a efectos adversos. Al hacerlo, dedicarás menos
tiempo a lograr que el programa vuelva a funcionar, impleme-
ntando y probando los cambios. Cuanto menos tiempo dedi-
ques a realizar cambios, más tiempo tendrás para implementar
funciones.
[email protected] (#160493)
41 Principios del diseño / Encapsula lo que varía #160493
puestos incluidos.
1 method getOrderTotal(order) is
2 total = 0
3 foreach item in order.lineItems
4 total += item.price * item.quantity
5
6 if (order.country == "US")
7 total += total * 0.07 // Impuesto sobre la venta de EUA
8 else if (order.country == "EU"):
9 total += total * 0.20 // IVA europeo
10
11 return total
ANTES: el código de cálculo del impuesto está mezclado con el resto del
código del método.
[email protected] (#160493)
42 Principios del diseño / Encapsula lo que varía #160493
1 method getOrderTotal(order) is
2 total = 0
3 foreach item in order.lineItems
4 total += item.price * item.quantity
5
6 total += total * getTaxRate(order.country)
7
8 return total
9
10 method getTaxRate(country) is
11 if (country == "US")
12 return 0.07 // Impuesto sobre la venta de EUA
13 else if (country == "EU")
14 return 0.20 // IVA europeo
15 else
16 return 0
[email protected] (#160493)
43 Principios del diseño / Encapsula lo que varía #160493
[email protected] (#160493)
44 Principios del diseño / Encapsula lo que varía #160493
[email protected] (#160493)
45 Principios del diseño / Programa a una interfaz, no a una implementación #160493
[email protected] (#160493)
46 Principios del diseño / Programa a una interfaz, no a una implementación #160493
[email protected] (#160493)
47 Principios del diseño / Programa a una interfaz, no a una implementación #160493
Ejemplo
Veamos otro ejemplo que ilustra que trabajar con objetos a
través de interfaces puede ser más beneficioso que depender
de sus clases concretas. Imagina que estás creando un simu-
lador de empresa de desarrollo de software. Tienes distintas
clases que representan varios tipos de empleados.
[email protected] (#160493)
48 Principios del diseño / Programa a una interfaz, no a una implementación #160493
[email protected] (#160493)
49 Principios del diseño / Programa a una interfaz, no a una implementación #160493
[email protected] (#160493)
50 Principios del diseño / Favorece la composición sobre la herencia #160493
[email protected] (#160493)
51 Principios del diseño / Favorece la composición sobre la herencia #160493
[email protected] (#160493)
52 Principios del diseño / Favorece la composición sobre la herencia #160493
Ejemplo
Imagina que debes crear una aplicación de un catálogo para
un fabricante de automóviles. La empresa fabrica autos y ca-
miones; pueden ser eléctricos o de gasolina; todos los mode-
los pueden tener controles manuales o piloto automático.
[email protected] (#160493)
53 Principios del diseño / Favorece la composición sobre la herencia #160493
[email protected] (#160493)
54 Principios SOLID #160493
Principios SOLID
Ahora que conoces los principios básicos de diseño, veamos
cinco que se conocen popularmente como los principios
SOLID. Robert Martin los presentó en el libro Desarrollo ágil de
1
software: principios, patrones y prácticas .
[email protected] (#160493)
55 Principios SOLID / S: Principio de responsabilidad única #160493
Hay más: si una clase hace demasiadas cosas, tienes que cambiarla
cada vez que una de esas cosas cambia. Al hacerlo, te arriesgas a
descomponer otras partes de la clase que no pretendías cambiar. Si
sientes que te resulta difícil centrarte en un aspecto específico del
programa cada vez, recuerda el principio de responsabilidad única
y comprueba si es el momento de dividir algunas clases en partes.
[email protected] (#160493)
56 Principios SOLID / S: Principio de responsabilidad única #160493
Ejemplo
La clase Empleado tiene varias razones para cambiar. La prime-
ra razón puede estar relacionada con el trabajo principal de la
clase: gestionar información de los empleados. Pero hay otra
razón: el formato del informe de horas de trabajo puede ca-
mbiar con el tiempo, lo que te obliga a cambiar el código de
la clase.
[email protected] (#160493)
57 Principios SOLID / O: Principio de abierto/cerrado #160493
O pen/Closed Principle
Principio de abierto/cerrado
[email protected] (#160493)
58 Principios SOLID / O: Principio de abierto/cerrado #160493
Ejemplo
Tienes una aplicación de comercio electrónico con una clase
Pedido que calcula los costos de envío, y todos los métodos
[email protected] (#160493)
59 Principios SOLID / O: Principio de abierto/cerrado #160493
[email protected] (#160493)
60 Principios SOLID / O: Principio de abierto/cerrado #160493
[email protected] (#160493)
61 Principios SOLID / L: Principio de sustitución de Liskov #160493
[email protected] (#160493)
62 Principios SOLID / L: Principio de sustitución de Liskov #160493
◦ Digamos que hay una clase con un método que debe ali-
mentar gatos: alimentar(Gato c) . El código cliente siempre
pasa objetos de gatos a este método.
[email protected] (#160493)
63 Principios SOLID / L: Principio de sustitución de Liskov #160493
◦ Digamos que
tienes una clase con el método
comprarGato(): Gato . El código cliente espera recibir cual-
[email protected] (#160493)
64 Principios SOLID / L: Principio de sustitución de Liskov #160493
[email protected] (#160493)
65 Principios SOLID / L: Principio de sustitución de Liskov #160493
[email protected] (#160493)
66 Principios SOLID / L: Principio de sustitución de Liskov #160493
Ejemplo
Veamos un ejemplo de una jerarquía de clases de documento
que violan el principio de sustitución.
[email protected] (#160493)
67 Principios SOLID / L: Principio de sustitución de Liskov #160493
[email protected] (#160493)
68 Principios SOLID / I: Principio de segregación de la interfaz #160493
[email protected] (#160493)
69 Principios SOLID / I: Principio de segregación de la interfaz #160493
Ejemplo
Imagina que creaste una biblioteca que facilita la integración de
aplicaciones con varios proveedores de computación en la nube.
Aunque en la versión inicial sólo soportaba Amazon Cloud, cubría
todos los servicios y funciones de la nube.
[email protected] (#160493)
70 Principios SOLID / I: Principio de segregación de la interfaz #160493
[email protected] (#160493)
71 Principios SOLID / D: Principio de inversión de la dependencia #160493
[email protected] (#160493)
72 Principios SOLID / D: Principio de inversión de la dependencia #160493
3. Una vez que las clases de bajo nivel implementan esas interfa-
ces, se vuelven dependientes del nivel de la lógica de negocio,
invirtiendo la dirección de la dependencia original.
Ejemplo
En este ejemplo, la clase de alto nivel — que se ocupa de in-
formes presupuestarios — utiliza una clase de base de datos
de bajo nivel para leer y almacenar su información. Esto si-
gnifica que cualquier cambio en la clase de bajo nivel, como
en el caso del lanzamiento de una nueva versión del servi-
[email protected] (#160493)
73 Principios SOLID / D: Principio de inversión de la dependencia #160493
ANTES: una clase de alto nivel depende de una clase de bajo nivel.
[email protected] (#160493)
74 Principios SOLID / D: Principio de inversión de la dependencia #160493
[email protected] (#160493)
#160493
EL CATÁLOGO
DE PATRONES
DE DISEÑO
[email protected] (#160493)
76 Patrones creacionales #160493
Patrones creacionales
Los patrones creacionales proporcionan varios mecanismos de
creación de objetos que incrementan la flexibilidad y la reuti-
lización del código existente.
Factory
Method
Proporciona una interfaz para la creación de objetos en una su-
perclase, mientras permite a las subclases alterar el tipo de obje-
tos que se crearán.
Abstract
Factory
Permite producir familias de objetos relacionados sin especificar
sus clases concretas.
[email protected] (#160493)
77 Patrones creacionales #160493
Builder
Permite construir objetos complejos paso a paso. Este patrón nos
permite producir distintos tipos y representaciones de un objeto
empleando el mismo código de construcción.
Prototype
Permite copiar objetos existentes sin que el código dependa de
sus clases.
Singleton
Permite asegurarnos de que una clase tenga una única instancia,
a la vez que proporciona un punto de acceso global a dicha insta-
ncia.
[email protected] (#160493)
78 Patrones creacionales / Factory Method #160493
FACTORY METHOD
También llamado: Método fábrica, Constructor virtual
[email protected] (#160493)
79 Patrones creacionales / Factory Method #160493
Problema
Imagina que estás creando una aplicación de gestión logística.
La primera versión de tu aplicación sólo es capaz de manejar
el transporte en camión, por lo que la mayor parte de tu códi-
go se encuentra dentro de la clase Camión .
[email protected] (#160493)
80 Patrones creacionales / Factory Method #160493
Solución
El patrón Factory Method sugiere que, en lugar de llamar al
operador new para construir objetos directamente, se invoque
a un método fábrica especial. No te preocupes: los objetos se
siguen creando a través del operador new , pero se invocan
desde el método fábrica. Los objetos devueltos por el método
fábrica a menudo se denominan productos.
[email protected] (#160493)
81 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
82 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
83 Patrones creacionales / Factory Method #160493
Estructura
[email protected] (#160493)
84 Patrones creacionales / Factory Method #160493
Pseudocódigo
Este ejemplo ilustra cómo puede utilizarse el patrón Factory
Method para crear elementos de interfaz de usuario (UI) multi-
plataforma sin acoplar el código cliente a clases UI concretas.
[email protected] (#160493)
85 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
86 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
87 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
88 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
89 Patrones creacionales / Factory Method #160493
Aplicabilidad
Utiliza el Método Fábrica cuando no conozcas de antemano las
dependencias y los tipos exactos de los objetos con los que
deba funcionar tu código.
[email protected] (#160493)
90 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
91 Patrones creacionales / Factory Method #160493
Cómo implementarlo
1. Haz que todos los productos sigan la misma interfaz. Esta inte-
rfaz deberá declarar métodos que tengan sentido en todos los
productos.
[email protected] (#160493)
92 Patrones creacionales / Factory Method #160493
como con objetos Tren . Puedes crear una nueva subclase (di-
[email protected] (#160493)
93 Patrones creacionales / Factory Method #160493
Pros y contras
Evitas un acoplamiento fuerte entre el creador y los productos
concretos.
Principio de responsabilidad única. Puedes mover el código de
creación de producto a un lugar del programa, haciendo que
el código sea más fácil de mantener.
Principio de abierto/cerrado. Puedes incorporar nuevos tipos de
productos en el programa sin descomponer el código cliente
existente.
[email protected] (#160493)
94 Patrones creacionales / Factory Method #160493
[email protected] (#160493)
95 Patrones creacionales / Abstract Factory #160493
ABSTRACT FACTORY
También llamado: Fábrica abstracta
[email protected] (#160493)
96 Patrones creacionales / Abstract Factory #160493
Problema
Imagina que estás creando un simulador de tienda de mue-
bles. Tu código está compuesto por clases que representan lo
siguiente:
[email protected] (#160493)
97 Patrones creacionales / Abstract Factory #160493
Solución
Lo primero que sugiere el patrón Abstract Factory es que de-
claremos de forma explícita interfaces para cada producto di-
ferente de la familia de productos (por ejemplo, silla, sofá
o mesilla). Después podemos hacer que todas las variantes
de los productos sigan esas interfaces. Por ejemplo, todas las
variantes de silla pueden implementar la interfaz Silla , así
[email protected] (#160493)
98 Patrones creacionales / Abstract Factory #160493
Todas las variantes del mismo objeto deben moverse a una única jerarquía
de clase.
[email protected] (#160493)
99 Patrones creacionales / Abstract Factory #160493
[email protected] (#160493)
100 Patrones creacionales / Abstract Factory #160493
[email protected] (#160493)
101 Patrones creacionales / Abstract Factory #160493
Estructura
[email protected] (#160493)
102 Patrones creacionales / Abstract Factory #160493
Pseudocódigo
Este ejemplo ilustra cómo puede utilizarse el patrón Abstract
Factory para crear elementos de interfaz de usuario (UI) multi-
plataforma sin acoplar el código cliente a clases UI concretas,
mientras se mantiene la consistencia de todos los elementos
creados respecto al sistema operativo seleccionado.
[email protected] (#160493)
103 Patrones creacionales / Abstract Factory #160493
[email protected] (#160493)
104 Patrones creacionales / Abstract Factory #160493
[email protected] (#160493)
105 Patrones creacionales / Abstract Factory #160493
10 method createCheckbox():Checkbox
11
12
13 // Las fábricas concretas producen una familia de productos que
14 // pertenecen a una única variante. La fábrica garantiza que los
15 // productos resultantes sean compatibles. Las firmas de los
16 // métodos de las fábricas concretas devuelven un producto
17 // abstracto mientras que dentro del método se instancia un
18 // producto concreto.
19 class WinFactory implements GUIFactory is
20 method createButton():Button is
21 return new WinButton()
22 method createCheckbox():Checkbox is
23 return new WinCheckbox()
24
25 // Cada fábrica concreta tiene una variante de producto
26 // correspondiente.
27 class MacFactory implements GUIFactory is
28 method createButton():Button is
29 return new MacButton()
30 method createCheckbox():Checkbox is
31 return new MacCheckbox()
32
33
34 // Cada producto individual de una familia de productos debe
35 // tener una interfaz base. Todas las variantes del producto
36 // deben implementar esta interfaz.
37 interface Button is
38 method paint()
39
40 // Los productos concretos son creados por las fábricas
41 // concretas correspondientes.
[email protected] (#160493)
106 Patrones creacionales / Abstract Factory #160493
[email protected] (#160493)
107 Patrones creacionales / Abstract Factory #160493
74 this
this.factory = factory
75 method createUI() is
76 this
this.button = factory.createButton()
77 method paint() is
78 button.paint()
79
80
81 // La aplicación elige el tipo de fábrica dependiendo de la
82 // configuración actual o de los ajustes del entorno y la crea
83 // durante el tiempo de ejecución (normalmente en la etapa de
84 // inicialización).
85 class ApplicationConfigurator is
86 method main() is
87 config = readApplicationConfigFile()
88
89 if (config.OS == "Windows") then
90 factory = new WinFactory()
91 else if (config.OS == "Mac") then
92 factory = new MacFactory()
93 else
94 throw new Exception("Error! Unknown operating system.")
95
96 Application app = new Application(factory)
Aplicabilidad
Utiliza el patrón Abstract Factory cuando tu código deba fun-
cionar con varias familias de productos relacionados, pero no
desees que dependa de las clases concretas de esos productos,
ya que puede ser que no los conozcas de antemano o sencilla-
mente quieras permitir una futura extensibilidad.
[email protected] (#160493)
108 Patrones creacionales / Abstract Factory #160493
Cómo implementarlo
1. Mapea una matriz de distintos tipos de productos frente a va-
riantes de dichos productos.
[email protected] (#160493)
109 Patrones creacionales / Abstract Factory #160493
Pros y contras
Puedes tener la certeza de que los productos que obtienes de
una fábrica son compatibles entre sí.
Evitas un acoplamiento fuerte entre productos concretos y el
código cliente.
Principio de responsabilidad única. Puedes mover el código de
creación de productos a un solo lugar, haciendo que el código
sea más fácil de mantener.
Principio de abierto/cerrado. Puedes introducir nuevas variantes
de productos sin descomponer el código cliente existente.
[email protected] (#160493)
110 Patrones creacionales / Abstract Factory #160493
[email protected] (#160493)
111 Patrones creacionales / Builder #160493
BUILDER
También llamado: Constructor
[email protected] (#160493)
112 Patrones creacionales / Builder #160493
Problema
Imagina un objeto complejo que requiere una inicialización la-
boriosa, paso a paso, de muchos campos y objetos anidados.
Normalmente, este código de inicialización está sepultado de-
ntro de un monstruoso constructor con una gran cantidad de
parámetros. O, peor aún: disperso por todo el código cliente.
[email protected] (#160493)
113 Patrones creacionales / Builder #160493
[email protected] (#160493)
114 Patrones creacionales / Builder #160493
Solución
El patrón Builder sugiere que saques el código de construcción
del objeto de su propia clase y lo coloques dentro de objetos
independientes llamados constructores.
[email protected] (#160493)
115 Patrones creacionales / Builder #160493
[email protected] (#160493)
116 Patrones creacionales / Builder #160493
Clase directora
[email protected] (#160493)
117 Patrones creacionales / Builder #160493
[email protected] (#160493)
118 Patrones creacionales / Builder #160493
Estructura
[email protected] (#160493)
119 Patrones creacionales / Builder #160493
Pseudocódigo
Este ejemplo del patrón Builder ilustra cómo se puede reuti-
lizar el mismo código de construcción de objetos a la hora
de construir distintos tipos de productos, como automóviles, y
crear los correspondientes manuales para esos automóviles.
[email protected] (#160493)
120 Patrones creacionales / Builder #160493
[email protected] (#160493)
121 Patrones creacionales / Builder #160493
[email protected] (#160493)
122 Patrones creacionales / Builder #160493
[email protected] (#160493)
123 Patrones creacionales / Builder #160493
[email protected] (#160493)
124 Patrones creacionales / Builder #160493
[email protected] (#160493)
125 Patrones creacionales / Builder #160493
93 method setEngine(...) is
94 // Añade instrucciones del motor.
95
96 method setTripComputer(...) is
97 // Añade instrucciones de la computadora de navegación.
98
99 method setGPS(...) is
100 // Añade instrucciones del GPS.
101
102 method getProduct():Manual is
103 // Devuelve el manual y rearma el constructor.
104
105
106 // El director sólo es responsable de ejecutar los pasos de
107 // construcción en una secuencia particular. Resulta útil cuando
108 // se crean productos de acuerdo con un orden o configuración
109 // específicos. En sentido estricto, la clase directora es
110 // opcional, ya que el cliente puede controlar directamente los
111 // objetos constructores.
112 class Director is
113 // El director funciona con cualquier instancia de
114 // constructor que le pase el código cliente. De esta forma,
115 // el código cliente puede alterar el tipo final del
116 // producto recién montado. El director puede construir
117 // multitud de variaciones de producto utilizando los mismos
118 // pasos de construcción.
119 method constructSportsCar(builder: Builder) is
120 builder.reset()
121 builder.setSeats(2)
122 builder.setEngine(new
new SportEngine())
123 builder.setTripComputer(true
true)
124 builder.setGPS(true
true)
[email protected] (#160493)
126 Patrones creacionales / Builder #160493
125
126 method constructSUV(builder: Builder) is
127 // ...
128
129
130 // El código cliente crea un objeto constructor, lo pasa al
131 // director y después inicia el proceso de construcción. El
132 // resultado final se extrae del objeto constructor.
133 class Application is
134
135 method makeCar() is
136 director = new Director()
137
138 CarBuilder builder = new CarBuilder()
139 director.constructSportsCar(builder)
140 Car car = builder.getProduct()
141
142 CarManualBuilder builder = new CarManualBuilder()
143 director.constructSportsCar(builder)
144
145 // El producto final a menudo se extrae de un objeto
146 // constructor, ya que el director no conoce y no
147 // depende de constructores y productos concretos.
148 Manual manual = builder.getProduct()
Aplicabilidad
Utiliza el patrón Builder para evitar un “constructor
telescópico”.
[email protected] (#160493)
127 Patrones creacionales / Builder #160493
1 class Pizza {
2 Pizza(int size) { ... }
3 Pizza(int size, boolean cheese) { ... }
4 Pizza(int size, boolean cheese, boolean pepperoni) { ... }
5 // ...
[email protected] (#160493)
128 Patrones creacionales / Builder #160493
Cómo implementarlo
1. Asegúrate de poder definir claramente los pasos comunes de
construcción para todas las representaciones disponibles del
producto. De lo contrario, no podrás proceder a implementar
el patrón.
[email protected] (#160493)
129 Patrones creacionales / Builder #160493
[email protected] (#160493)
130 Patrones creacionales / Builder #160493
Pros y contras
Puedes construir objetos paso a paso, aplazar pasos de la con-
strucción o ejecutar pasos de forma recursiva.
Puedes reutilizar el mismo código de construcción al construir
varias representaciones de productos.
Principio de responsabilidad única. Puedes aislar un código de
construcción complejo de la lógica de negocio del producto.
[email protected] (#160493)
131 Patrones creacionales / Builder #160493
[email protected] (#160493)
132 Patrones creacionales / Prototype #160493
PROTOTYPE
También llamado: Prototipo, Clon, Clone
[email protected] (#160493)
133 Patrones creacionales / Prototype #160493
Problema
Digamos que tienes un objeto y quieres crear una copia exacta
de él. ¿Cómo lo harías? En primer lugar, debes crear un nuevo
objeto de la misma clase. Después debes recorrer todos los
campos del objeto original y copiar sus valores en el nuevo
objeto.
Hay otro problema con el enfoque directo. Dado que debes co-
nocer la clase del objeto para crear un duplicado, el código
se vuelve dependiente de esa clase. Si esta dependencia adi-
cional no te da miedo, todavía hay otra trampa. En ocasiones
tan solo conocemos la interfaz que sigue el objeto, pero no su
[email protected] (#160493)
134 Patrones creacionales / Prototype #160493
Solución
El patrón Prototype delega el proceso de clonación a los pro-
pios objetos que están siendo clonados. El patrón declara una
interfaz común para todos los objetos que soportan la clona-
ción. Esta interfaz nos permite clonar un objeto sin acoplar el
código a la clase de ese objeto. Normalmente, dicha interfaz
contiene un único método clonar .
[email protected] (#160493)
135 Patrones creacionales / Prototype #160493
[email protected] (#160493)
136 Patrones creacionales / Prototype #160493
[email protected] (#160493)
137 Patrones creacionales / Prototype #160493
Estructura
Implementación básica
[email protected] (#160493)
138 Patrones creacionales / Prototype #160493
[email protected] (#160493)
139 Patrones creacionales / Prototype #160493
Pseudocódigo
En este ejemplo, el patrón Prototype nos permite producir co-
pias exactas de objetos geométricos sin acoplar el código a sus
clases.
1 // Prototipo base.
2 abstract class Shape is
3 field X: int
[email protected] (#160493)
140 Patrones creacionales / Prototype #160493
4 field Y: int
5 field color: string
6
7 // Un constructor normal.
8 constructor Shape() is
9 // ...
10
11 // El constructor prototipo. Un nuevo objeto se inicializa
12 // con valores del objeto existente.
13 constructor Shape(source: Shape) is
14 this
this()
15 this
this.X = source.X
16 this
this.Y = source.Y
17 this
this.color = source.color
18
19 // La operación clonar devuelve una de las subclases de
20 // Shape (Forma).
21 abstract method clone():Shape
22
23
24 // Prototipo concreto. El método de clonación crea un nuevo
25 // objeto y lo pasa al constructor. Hasta que el constructor
26 // termina, tiene una referencia a un nuevo clon. De este modo
27 // nadie tiene acceso a un clon a medio terminar. Esto garantiza
28 // la consistencia del resultado de la clonación.
29 class Rectangle extends Shape is
30 field width: int
31 field height: int
32
33 constructor Rectangle(source: Rectangle) is
34 // Para copiar campos privados definidos en la clase
35 // padre es necesaria una llamada a un constructor
[email protected] (#160493)
141 Patrones creacionales / Prototype #160493
36 // padre.
37 super
super(source)
38 this
this.width = source.width
39 this
this.height = source.height
40
41 method clone():Shape is
42 return new Rectangle(this
this)
43
44
45 class Circle extends Shape is
46 field radius: int
47
48 constructor Circle(source: Circle) is
49 super
super(source)
50 this
this.radius = source.radius
51
52 method clone():Shape is
53 return new Circle(this
this)
54
55
56 // En alguna parte del código cliente.
57 class Application is
58 field shapes: array of Shape
59
60 constructor Application() is
61 Circle circle = new Circle()
62 circle.X = 10
63 circle.Y = 10
64 circle.radius = 20
65 shapes.add(circle)
66
67 Circle anotherCircle = circle.clone()
[email protected] (#160493)
142 Patrones creacionales / Prototype #160493
68 shapes.add(anotherCircle)
69 // La variable `anotherCircle` (otroCírculo) contiene
70 // una copia exacta del objeto `circle`.
71
72 Rectangle rectangle = new Rectangle()
73 rectangle.width = 10
74 rectangle.height = 20
75 shapes.add(rectangle)
76
77 method businessLogic() is
78 // Prototype es genial porque te permite producir una
79 // copia de un objeto sin conocer nada de su tipo.
80 Array shapesCopy = new Array of Shapes.
81
82 // Por ejemplo, no conocemos los elementos exactos de la
83 // matriz de formas. Lo único que sabemos es que son
84 // todas formas. Pero, gracias al polimorfismo, cuando
85 // invocamos el método `clonar` en una forma, el
86 // programa comprueba su clase real y ejecuta el método
87 // de clonación adecuado definido en dicha clase. Por
88 // eso obtenemos los clones adecuados en lugar de un
89 // grupo de simples objetos Shape.
90 foreach (s in shapes) do
91 shapesCopy.add(s.clone())
92
93 // La matriz `shapesCopy` contiene copias exactas del
94 // hijo de la matriz `shape`.
[email protected] (#160493)
143 Patrones creacionales / Prototype #160493
Aplicabilidad
Utiliza el patrón Prototype cuando tu código no deba depender
de las clases concretas de objetos que necesites copiar.
[email protected] (#160493)
144 Patrones creacionales / Prototype #160493
Cómo implementarlo
1. Crea la interfaz del prototipo y declara el método clonar en
ella, o, simplemente, añade el método a todas las clases de
una jerarquía de clase existente, si la tienes.
[email protected] (#160493)
145 Patrones creacionales / Prototype #160493
Pros y contras
Puedes clonar objetos sin acoplarlos a sus clases concretas.
[email protected] (#160493)
146 Patrones creacionales / Prototype #160493
[email protected] (#160493)
147 Patrones creacionales / Prototype #160493
[email protected] (#160493)
148 Patrones creacionales / Singleton #160493
SINGLETON
También llamado: Instancia única
[email protected] (#160493)
149 Patrones creacionales / Singleton #160493
Problema
El patrón Singleton resuelve dos problemas al mismo tiempo,
vulnerando el Principio de responsabilidad única:
1. Garantizar que una clase tenga una única instancia. ¿Por qué
querría alguien controlar cuántas instancias tiene una clase?
El motivo más habitual es controlar el acceso a algún recurso
compartido, por ejemplo, una base de datos o un archivo.
Puede ser que los clientes ni siquiera se den cuenta de que trabajan con el
mismo objeto todo el tiempo.
[email protected] (#160493)
150 Patrones creacionales / Singleton #160493
Solución
Todas las implementaciones del patrón Singleton tienen estos
dos pasos en común:
[email protected] (#160493)
151 Patrones creacionales / Singleton #160493
[email protected] (#160493)
152 Patrones creacionales / Singleton #160493
Estructura
pia clase.
Pseudocódigo
En este ejemplo, la clase de conexión de la base de datos actúa
como Singleton. Esta clase no tiene un constructor público,
por lo que la única manera de obtener su objeto es invocando
el método obtenerInstancia . Este método almacena en caché
[email protected] (#160493)
153 Patrones creacionales / Singleton #160493
[email protected] (#160493)
154 Patrones creacionales / Singleton #160493
Aplicabilidad
Utiliza el patrón Singleton cuando una clase de tu programa
tan solo deba tener una instancia disponible para todos los
clientes; por ejemplo, un único objeto de base de datos com-
partido por distintas partes del programa.
[email protected] (#160493)
155 Patrones creacionales / Singleton #160493
Cómo implementarlo
1. Añade un campo estático privado a la clase para almacenar la
instancia Singleton.
[email protected] (#160493)
156 Patrones creacionales / Singleton #160493
Pros y contras
Puedes tener la certeza de que una clase tiene una única
instancia.
Obtienes un punto de acceso global a dicha instancia.
[email protected] (#160493)
157 Patrones creacionales / Singleton #160493
[email protected] (#160493)
158 Patrones estructurales #160493
Patrones estructurales
Los patrones estructurales explican cómo ensamblar objetos y
clases en estructuras más grandes, a la vez que se mantiene la
flexibilidad y eficiencia de estas estructuras.
Adapter
Permite la colaboración entre objetos con interfaces incompati-
bles.
Bridge
Permite dividir una clase grande o un grupo de clases estrecha-
mente relacionadas, en dos jerarquías separadas (abstracción e
implementación) que pueden desarrollarse independientemente
la una de la otra.
[email protected] (#160493)
159 Patrones estructurales #160493
Composite
Permite componer objetos en estructuras de árbol y trabajar con
esas estructuras como si fueran objetos individuales.
Decorator
Permite añadir funcionalidades a objetos colocando estos objetos
dentro de objetos encapsuladores especiales que contienen estas
funcionalidades.
Facade
Proporciona una interfaz simplificada a una biblioteca, un frame-
work o cualquier otro grupo complejo de clases.
[email protected] (#160493)
160 Patrones estructurales #160493
Flyweight
Permite mantener más objetos dentro de la cantidad disponible
de memoria RAM compartiendo las partes comunes del estado
entre varios objetos en lugar de mantener toda la información en
cada objeto.
Proxy
Permite proporcionar un sustituto o marcador de posición para
otro objeto. Un proxy controla el acceso al objeto original, permi-
tiéndote hacer algo antes o después de que la solicitud llegue al
objeto original.
[email protected] (#160493)
161 Patrones estructurales / Adapter #160493
ADAPTER
También llamado: Adaptador, Envoltorio, Wrapper
[email protected] (#160493)
162 Patrones estructurales / Adapter #160493
Problema
Imagina que estás creando una aplicación de monitoreo del
mercado de valores. La aplicación descarga la información de
bolsa desde varias fuentes en formato XML para presentarla al
usuario con bonitos gráficos y diagramas.
[email protected] (#160493)
163 Patrones estructurales / Adapter #160493
Solución
Puedes crear un adaptador. Se trata de un objeto especial que
convierte la interfaz de un objeto, de forma que otro objeto
pueda comprenderla.
[email protected] (#160493)
164 Patrones estructurales / Adapter #160493
[email protected] (#160493)
165 Patrones estructurales / Adapter #160493
Estructura
Adaptador de objetos
[email protected] (#160493)
166 Patrones estructurales / Adapter #160493
[email protected] (#160493)
167 Patrones estructurales / Adapter #160493
Clase adaptadora
[email protected] (#160493)
168 Patrones estructurales / Adapter #160493
Pseudocódigo
Este ejemplo del patrón Adapter se basa en el clásico conflicto
entre piezas cuadradas y agujeros redondos.
[email protected] (#160493)
169 Patrones estructurales / Adapter #160493
[email protected] (#160493)
170 Patrones estructurales / Adapter #160493
Aplicabilidad
Utiliza la clase adaptadora cuando quieras usar una clase exi-
stente, pero cuya interfaz no sea compatible con el resto del
código.
[email protected] (#160493)
171 Patrones estructurales / Adapter #160493
Cómo implementarlo
1. Asegúrate de que tienes al menos dos clases con interfaces in-
compatibles:
[email protected] (#160493)
172 Patrones estructurales / Adapter #160493
[email protected] (#160493)
173 Patrones estructurales / Adapter #160493
Pros y contras
Principio de responsabilidad única. Puedes separar la interfaz o
el código de conversión de datos de la lógica de negocio pri-
maria del programa.
Principio de abierto/cerrado. Puedes introducir nuevos tipos de
adaptadores al programa sin descomponer el código cliente
existente, siempre y cuando trabajen con los adaptadores a
través de la interfaz con el cliente.
[email protected] (#160493)
174 Patrones estructurales / Adapter #160493
[email protected] (#160493)
175 Patrones estructurales / Bridge #160493
BRIDGE
También llamado: Puente
[email protected] (#160493)
176 Patrones estructurales / Bridge #160493
Problema
¿Abstracción? ¿Implementación? ¿Asusta? Mantengamos la
calma y veamos un ejemplo sencillo.
[email protected] (#160493)
177 Patrones estructurales / Bridge #160493
Solución
Este problema se presenta porque intentamos extender las
clases de forma en dos dimensiones independientes: por forma
y por color. Es un problema muy habitual en la herencia de
clases.
[email protected] (#160493)
178 Patrones estructurales / Bridge #160493
Abstracción e implementación
1
El libro de la GoF introduce los términos Abstracción e Imple-
mentación como parte de la definición del patrón Bridge. En
mi opinión, los términos suenan demasiado académicos y pro-
vocan que el patrón parezca más complicado de lo que es en
realidad. Una vez leído el sencillo ejemplo con las formas y los
colores, vamos a descifrar el significado que esconden las te-
mibles palabras del libro de esta banda de cuatro.
[email protected] (#160493)
179 Patrones estructurales / Bridge #160493
[email protected] (#160493)
180 Patrones estructurales / Bridge #160493
[email protected] (#160493)
181 Patrones estructurales / Bridge #160493
[email protected] (#160493)
182 Patrones estructurales / Bridge #160493
Estructura
[email protected] (#160493)
183 Patrones estructurales / Bridge #160493
Pseudocódigo
Este ejemplo ilustra cómo puede ayudar el patrón Bridge a
dividir el código monolítico de una aplicación que gestiona
dispositivos y sus controles remotos. Las clases Dispositivo
actúan como implementación, mientras que las clases Remoto
actúan como abstracción.
[email protected] (#160493)
184 Patrones estructurales / Bridge #160493
[email protected] (#160493)
185 Patrones estructurales / Bridge #160493
[email protected] (#160493)
186 Patrones estructurales / Bridge #160493
28 device.setVolume(0)
29
30
31 // La interfaz de "implementación" declara métodos comunes a
32 // todas las clases concretas de implementación. No tiene por
33 // qué coincidir con la interfaz de la abstracción. De hecho,
34 // las dos interfaces pueden ser completamente diferentes.
35 // Normalmente, la interfaz de implementación únicamente
36 // proporciona operaciones primitivas, mientras que la
37 // abstracción define operaciones de más alto nivel con base en
38 // las primitivas.
39 interface Device is
40 method isEnabled()
41 method enable()
42 method disable()
43 method getVolume()
44 method setVolume(percent)
45 method getChannel()
46 method setChannel(channel)
47
48
49 // Todos los dispositivos siguen la misma interfaz.
50 class Tv implements Device is
51 // ...
52
53 class Radio implements Device is
54 // ...
55
56
57 // En algún lugar del código cliente.
58 tv = new Tv()
59 remote = new RemoteControl(tv)
[email protected] (#160493)
187 Patrones estructurales / Bridge #160493
60 remote.togglePower()
61
62 radio = new Radio()
63 remote = new AdvancedRemoteControl(radio)
Aplicabilidad
Utiliza el patrón Bridge cuando quieras dividir y organizar una
clase monolítica que tenga muchas variantes de una sola fun-
cionalidad (por ejemplo, si la clase puede trabajar con diversos
servidores de bases de datos).
[email protected] (#160493)
188 Patrones estructurales / Bridge #160493
Por cierto, este último punto es la razón principal por la que tanta
gente confunde el patrón Bridge con el patrón Strategy. Recuerda
que un patrón es algo más que un cierto modo de estructurar tus
clases. También puede comunicar intención y el tipo de problema
que se está abordando.
Cómo implementarlo
1. Identifica las dimensiones ortogonales de tus clases. Estos co-
nceptos independientes pueden ser: abstracción/plataforma,
dominio/infraestructura, front end/back end, o interfaz/imple-
mentación.
[email protected] (#160493)
189 Patrones estructurales / Bridge #160493
Pros y contras
Puedes crear clases y aplicaciones independientes de
plataforma.
El código cliente funciona con abstracciones de alto nivel. No
está expuesto a los detalles de la plataforma.
[email protected] (#160493)
190 Patrones estructurales / Bridge #160493
[email protected] (#160493)
191 Patrones estructurales / Bridge #160493
[email protected] (#160493)
192 Patrones estructurales / Composite #160493
COMPOSITE
También llamado: Objeto compuesto, Object Tree
[email protected] (#160493)
193 Patrones estructurales / Composite #160493
Problema
El uso del patrón Composite sólo tiene sentido cuando el modelo
central de tu aplicación puede representarse en forma de árbol.
[email protected] (#160493)
194 Patrones estructurales / Composite #160493
Solución
El patrón Composite sugiere que trabajes con Productos y
Cajas a través de una interfaz común que declara un método
[email protected] (#160493)
195 Patrones estructurales / Composite #160493
[email protected] (#160493)
196 Patrones estructurales / Composite #160493
Estructura
[email protected] (#160493)
197 Patrones estructurales / Composite #160493
[email protected] (#160493)
198 Patrones estructurales / Composite #160493
Pseudocódigo
En este ejemplo, el patrón Composite te permite implementar
el apilamiento (stacking) de formas geométricas en un editor
gráfico.
[email protected] (#160493)
199 Patrones estructurales / Composite #160493
que una forma simple. Sin embargo, en lugar de hacer algo por
su cuenta, una forma compuesta pasa la solicitud de forma re-
cursiva a todos sus hijos y “suma” el resultado.
[email protected] (#160493)
200 Patrones estructurales / Composite #160493
20 method draw() is
21 // Dibuja un punto en X e Y.
22
23 // Todas las clases de componente pueden extender otros
24 // componentes.
25 class Circle extends Dot is
26 field radius
27
28 constructor Circle(x, y, radius) { ... }
29
30 method draw() is
31 // Dibuja un círculo en X y Y con radio R.
32
33 // La clase compuesta representa componentes complejos que
34 // pueden tener hijos. Normalmente los objetos compuestos
35 // delegan el trabajo real a sus hijos y después "recapitulan"
36 // el resultado.
37 class CompoundGraphic implements Graphic is
38 field children: array of Graphic
39
40 // Un objeto compuesto puede añadir o eliminar otros
41 // componentes (tanto simples como complejos) a o desde su
42 // lista hija.
43 method add(child: Graphic) is
44 // Añade un hijo a la matriz de hijos.
45
46 method remove(child: Graphic) is
47 // Elimina un hijo de la matriz de hijos.
48
49 method move(x, y) is
50 foreach (child in children) do
51 child.move(x, y)
[email protected] (#160493)
201 Patrones estructurales / Composite #160493
52
53 // Un compuesto ejecuta su lógica primaria de una forma
54 // particular. Recorre recursivamente todos sus hijos,
55 // recopilando y recapitulando sus resultados. Debido a que
56 // los hijos del compuesto pasan esas llamadas a sus propios
57 // hijos y así sucesivamente, se recorre todo el árbol de
58 // objetos como resultado.
59 method draw() is
60 // 1. Para cada componente hijo:
61 // - Dibuja el componente.
62 // - Actualiza el rectángulo delimitador.
63 // 2. Dibuja un rectángulo de línea punteada utilizando
64 // las coordenadas de delimitación.
65
66
67 // El código cliente trabaja con todos los componentes a través
68 // de su interfaz base. De esta forma el código cliente puede
69 // soportar componentes de hoja simples así como compuestos
70 // complejos.
71 class ImageEditor is
72 field all: CompoundGraphic
73
74 method load() is
75 all = new CompoundGraphic()
76 all.add(new
new Dot(1, 2))
77 all.add(new
new Circle(5, 3, 10))
78 // ...
79
80 // Combina componentes seleccionados para formar un
81 // componente compuesto complejo.
82 method groupSelected(components: array of Graphic) is
83 group = new CompoundGraphic()
[email protected] (#160493)
202 Patrones estructurales / Composite #160493
Aplicabilidad
Utiliza el patrón Composite cuando tengas que implementar
una estructura de objetos con forma de árbol.
[email protected] (#160493)
203 Patrones estructurales / Composite #160493
Cómo implementarlo
1. Asegúrate de que el modelo central de tu aplicación pueda re-
presentarse como una estructura de árbol. Intenta dividirlo en
elementos simples y contenedores. Recuerda que los contene-
dores deben ser capaces de contener tanto elementos simples
como otros contenedores.
[email protected] (#160493)
204 Patrones estructurales / Composite #160493
Pros y contras
Puedes trabajar con estructuras de árbol complejas con mayor
comodidad: utiliza el polimorfismo y la recursión en tu favor.
Principio de abierto/cerrado. Puedes introducir nuevos tipos de
elemento en la aplicación sin descomponer el código existen-
te, que ahora funciona con el árbol de objetos.
[email protected] (#160493)
205 Patrones estructurales / Composite #160493
[email protected] (#160493)
206 Patrones estructurales / Decorator #160493
DECORATOR
También llamado: Decorador, Envoltorio, Wrapper
[email protected] (#160493)
207 Patrones estructurales / Decorator #160493
Problema
Imagina que estás trabajando en una biblioteca de notificacio-
nes que permite a otros programas notificar a sus usuarios ace-
rca de eventos importantes.
[email protected] (#160493)
208 Patrones estructurales / Decorator #160493
[email protected] (#160493)
209 Patrones estructurales / Decorator #160493
Solución
Cuando tenemos que alterar la funcionalidad de un objeto, lo
primero que se viene a la mente es extender una clase. No ob-
stante, la herencia tiene varias limitaciones importantes de las
que debes ser consciente.
[email protected] (#160493)
210 Patrones estructurales / Decorator #160493
[email protected] (#160493)
211 Patrones estructurales / Decorator #160493
[email protected] (#160493)
212 Patrones estructurales / Decorator #160493
[email protected] (#160493)
213 Patrones estructurales / Decorator #160493
[email protected] (#160493)
214 Patrones estructurales / Decorator #160493
Estructura
[email protected] (#160493)
215 Patrones estructurales / Decorator #160493
Pseudocódigo
En este ejemplo, el patrón Decorator te permite comprimir y
encriptar información delicada independientemente del códi-
go que utiliza esos datos.
[email protected] (#160493)
216 Patrones estructurales / Decorator #160493
[email protected] (#160493)
217 Patrones estructurales / Decorator #160493
• Después de que los datos son leídos del disco, pasan por los
mismos decoradores, que los descomprimen y decodifican.
[email protected] (#160493)
218 Patrones estructurales / Decorator #160493
[email protected] (#160493)
219 Patrones estructurales / Decorator #160493
[email protected] (#160493)
220 Patrones estructurales / Decorator #160493
[email protected] (#160493)
221 Patrones estructurales / Decorator #160493
121 if (enabledCompression)
122 source = new CompressionDecorator(source)
123
124 logger = new SalaryManager(source)
125 salary = logger.load()
126 // ...
Aplicabilidad
Utiliza el patrón Decorator cuando necesites asignar funciona-
lidades adicionales a objetos durante el tiempo de ejecución
sin descomponer el código que utiliza esos objetos.
[email protected] (#160493)
222 Patrones estructurales / Decorator #160493
Cómo implementarlo
1. Asegúrate de que tu dominio de negocio puede representar-
se como un componente primario con varias capas opcionales
encima.
4. Crea una clase base decoradora. Debe tener un campo para al-
macenar una referencia a un objeto envuelto. El campo debe
declararse con el tipo de interfaz de componente para permitir
la vinculación a componentes concretos, así como a decorado-
res. La clase decoradora base debe delegar todas las operacio-
nes al objeto envuelto.
[email protected] (#160493)
223 Patrones estructurales / Decorator #160493
Pros y contras
Puedes extender el comportamiento de un objeto sin crear una
nueva subclase.
Puedes añadir o eliminar responsabilidades de un objeto dura-
nte el tiempo de ejecución.
Puedes combinar varios comportamientos envolviendo un ob-
jeto con varios decoradores.
Principio de responsabilidad única. Puedes dividir una clase mo-
nolítica que implementa muchas variantes posibles de compo-
rtamiento, en varias clases más pequeñas.
[email protected] (#160493)
224 Patrones estructurales / Decorator #160493
[email protected] (#160493)
225 Patrones estructurales / Decorator #160493
[email protected] (#160493)
226 Patrones estructurales / Facade #160493
FACADE
También llamado: Fachada
[email protected] (#160493)
227 Patrones estructurales / Facade #160493
Problema
Imagina que debes lograr que tu código trabaje con un amplio
grupo de objetos que pertenecen a una sofisticada biblioteca o
framework. Normalmente, debes inicializar todos esos objetos,
llevar un registro de las dependencias, ejecutar los métodos
en el orden correcto y así sucesivamente.
Solución
Una fachada es una clase que proporciona una interfaz si-
mple a un subsistema complejo que contiene muchas partes
móviles. Una fachada puede proporcionar una funcionalidad
limitada en comparación con trabajar directamente con el sub-
sistema. Sin embargo, tan solo incluye las funciones realmente
importantes para los clientes.
[email protected] (#160493)
228 Patrones estructurales / Facade #160493
[email protected] (#160493)
229 Patrones estructurales / Facade #160493
Estructura
[email protected] (#160493)
230 Patrones estructurales / Facade #160493
Pseudocódigo
En este ejemplo, el patrón Facade simplifica la interacción con
un framework complejo de conversión de vídeo.
[email protected] (#160493)
231 Patrones estructurales / Facade #160493
[email protected] (#160493)
232 Patrones estructurales / Facade #160493
27 class VideoConverter is
28 method convert(filename, format):File is
29 file = new VideoFile(filename)
30 sourceCodec = (new
new CodecFactory).extract(file)
31 if (format == "mp4")
32 destinationCodec = new MPEG4CompressionCodec()
33 else
34 destinationCodec = new OggCompressionCodec()
35 buffer = BitrateReader.read(filename, sourceCodec)
36 result = BitrateReader.convert(buffer, destinationCodec)
37 result = (new
new AudioMixer()).fix(result)
38 return new File(result)
39
40 // Las clases Application no dependen de un millón de clases
41 // proporcionadas por el complejo framework. Además, si decides
42 // cambiar los frameworks, sólo tendrás de volver a escribir la
43 // clase fachada.
44 class Application is
45 method main() is
46 convertor = new VideoConverter()
47 mp4 = convertor.convert("funny-cats-video.ogg", "mp4")
48 mp4.save()
Aplicabilidad
Utiliza el patrón Facade cuando necesites una interfaz limitada
pero directa a un subsistema complejo.
[email protected] (#160493)
233 Patrones estructurales / Facade #160493
Cómo implementarlo
1. Comprueba si es posible proporcionar una interfaz más simple
que la que está proporcionando un subsistema existente. Estás
bien encaminado si esta interfaz hace que el código cliente sea
independiente de muchas de las clases del subsistema.
[email protected] (#160493)
234 Patrones estructurales / Facade #160493
Pros y contras
Puedes aislar tu código de la complejidad de un subsistema.
[email protected] (#160493)
235 Patrones estructurales / Facade #160493
[email protected] (#160493)
236 Patrones estructurales / Facade #160493
[email protected] (#160493)
237 Patrones estructurales / Flyweight #160493
FLYWEIGHT
También llamado: Peso mosca, Peso ligero, Cache
[email protected] (#160493)
238 Patrones estructurales / Flyweight #160493
Problema
Para divertirte un poco después de largas horas de trabajo, de-
cides crear un sencillo videojuego en el que los jugadores se
tienen que mover por un mapa disparándose entre sí. Decides
implementar un sistema de partículas realistas que lo distin-
ga de otros juegos. Grandes cantidades de balas, misiles y me-
tralla de las explosiones volarán por todo el mapa, ofreciendo
una apasionante experiencia al jugador.
[email protected] (#160493)
239 Patrones estructurales / Flyweight #160493
Solución
Observando más atentamente la clase Partícula , puede ser
que te hayas dado cuenta de que los campos de color y spri-
te consumen mucha más memoria que otros campos. Lo que
es peor, esos dos campos almacenan información casi idéntica
de todas las partículas. Por ejemplo, todas las balas tienen el
mismo color y sprite.
[email protected] (#160493)
240 Patrones estructurales / Flyweight #160493
[email protected] (#160493)
241 Patrones estructurales / Flyweight #160493
[email protected] (#160493)
242 Patrones estructurales / Flyweight #160493
[email protected] (#160493)
243 Patrones estructurales / Flyweight #160493
Flyweight y la inmutabilidad
Fábrica flyweight
[email protected] (#160493)
244 Patrones estructurales / Flyweight #160493
Estructura
[email protected] (#160493)
245 Patrones estructurales / Flyweight #160493
[email protected] (#160493)
246 Patrones estructurales / Flyweight #160493
Pseudocódigo
En este ejemplo, el patrón Flyweight ayuda a reducir el uso de
memoria a la hora de representar millones de objetos de árbol
en un lienzo.
[email protected] (#160493)
247 Patrones estructurales / Flyweight #160493
[email protected] (#160493)
248 Patrones estructurales / Flyweight #160493
33
34 // El objeto contextual contiene la parte extrínseca del estado
35 // del árbol. Una aplicación puede crear millones de ellas, ya
36 // que son muy pequeñas: dos coordenadas en números enteros y un
37 // campo de referencia.
38 class Tree is
39 field x,y
40 field type: TreeType
41 constructor Tree(x, y, type) { ... }
42 method draw(canvas) is
43 type.draw(canvas, this
this.x, this
this.y)
44
45 // Las clases Tree y Forest son los clientes de flyweight.
46 // Puedes fusionarlas si no tienes la intención de desarrollar
47 // más la clase Tree.
48 class Forest is
49 field trees: collection of Trees
50
51 method plantTree(x, y, name, color, texture) is
52 type = TreeFactory.getTreeType(name, color, texture)
53 tree = new Tree(x, y, type)
54 trees.add(tree)
55
56 method draw(canvas) is
57 foreach (tree in trees) do
58 tree.draw(canvas)
[email protected] (#160493)
249 Patrones estructurales / Flyweight #160493
Aplicabilidad
Utiliza el patrón Flyweight únicamente cuando tu programa
deba soportar una enorme cantidad de objetos que apenas
quepan en la RAM disponible.
Cómo implementarlo
1. Divide los campos de una clase que se convertirá en flyweight
en dos partes:
[email protected] (#160493)
250 Patrones estructurales / Flyweight #160493
Pros y contras
Puedes ahorrar mucha RAM, siempre que tu programa tenga
toneladas de objetos similares.
Puede que estés cambiando RAM por ciclos CPU cuando deba
calcularse de nuevo parte de la información de contexto cada
vez que alguien invoque un método flyweight.
[email protected] (#160493)
251 Patrones estructurales / Flyweight #160493
[email protected] (#160493)
252 Patrones estructurales / Proxy #160493
PROXY
Proxy es un patrón de diseño estructural que te permite propo-
rcionar un sustituto o marcador de posición para otro objeto.
Un proxy controla el acceso al objeto original, permitiéndote
hacer algo antes o después de que la solicitud llegue al obje-
to original.
[email protected] (#160493)
253 Patrones estructurales / Proxy #160493
Problema
¿Por qué querrías controlar el acceso a un objeto? Imagina que
tienes un objeto enorme que consume una gran cantidad de
recursos del sistema. Lo necesitas de vez en cuando, pero no
siempre.
[email protected] (#160493)
254 Patrones estructurales / Proxy #160493
Solución
El patrón Proxy sugiere que crees una nueva clase proxy con la
misma interfaz que un objeto de servicio original. Después ac-
tualizas tu aplicación para que pase el objeto proxy a todos los
clientes del objeto original. Al recibir una solicitud de un clie-
nte, el proxy crea un objeto de servicio real y le delega todo el
trabajo.
[email protected] (#160493)
255 Patrones estructurales / Proxy #160493
Las tarjetas de crédito pueden utilizarse para realizar pagos tanto como
el efectivo.
[email protected] (#160493)
256 Patrones estructurales / Proxy #160493
Estructura
[email protected] (#160493)
257 Patrones estructurales / Proxy #160493
Pseudocódigo
Este ejemplo ilustra cómo el patrón Proxy puede ayudar a
introducir la inicialización diferida y el almacenamiento en
caché a una biblioteca de integración de YouTube de un
tercero.
[email protected] (#160493)
258 Patrones estructurales / Proxy #160493
[email protected] (#160493)
259 Patrones estructurales / Proxy #160493
19
20 method downloadVideo(id) is
21 // Descarga un archivo de video de YouTube.
22
23 // Para ahorrar ancho de banda, podemos guardar en caché
24 // resultados de la solicitud durante algún tiempo, pero se
25 // puede colocar este código directamente dentro de la clase de
26 // servicio. Por ejemplo, puede haberse proporcionado como parte
27 // de la biblioteca de un tercero y/o definido como `final`. Por
28 // eso colocamos el código de almacenamiento en caché dentro de
29 // una nueva clase proxy que implementa la misma interfaz que la
30 // clase servicio. Delega al objeto de servicio únicamente
31 // cuando deben enviarse las solicitudes reales.
32 class CachedYouTubeClass implements ThirdPartyYouTubeLib is
33 private field service: ThirdPartyYouTubeLib
34 private field listCache, videoCache
35 field needReset
36
37 constructor CachedYouTubeClass(service: ThirdPartyYouTubeLib) is
38 this
this.service = service
39
40 method listVideos() is
41 if (listCache == null || needReset)
42 listCache = service.listVideos()
43 return listCache
44
45 method getVideoInfo(id) is
46 if (videoCache == null || needReset)
47 videoCache = service.getVideoInfo(id)
48 return videoCache
49
50 method downloadVideo(id) is
[email protected] (#160493)
260 Patrones estructurales / Proxy #160493
51 if (!downloadExists(id) || needReset)
52 service.downloadVideo(id)
53
54 // La clase GUI, que solía trabajar directamente con un objeto
55 // de servicio, permanece sin cambios siempre y cuando trabaje
56 // con el objeto de servicio a través de una interfaz. Podemos
57 // pasar sin riesgo un objeto proxy en lugar de un objeto de
58 // servicio real, ya que ambos implementan la misma interfaz.
59 class YouTubeManager is
60 protected field service: ThirdPartyYouTubeLib
61
62 constructor YouTubeManager(service: ThirdPartyYouTubeLib) is
63 this
this.service = service
64
65 method renderVideoPage(id) is
66 info = service.getVideoInfo(id)
67 // Representa la página del video.
68
69 method renderListPanel() is
70 list = service.listVideos()
71 // Representa la lista de miniaturas de los videos.
72
73 method reactOnUserInput() is
74 renderVideoPage()
75 renderListPanel()
76
77 // La aplicación puede configurar proxies sobre la marcha.
78 class Application is
79 method init() is
80 aYouTubeService = new ThirdPartyYouTubeClass()
81 aYouTubeProxy = new CachedYouTubeClass(aYouTubeService)
82 manager = new YouTubeManager(aYouTubeProxy)
[email protected] (#160493)
261 Patrones estructurales / Proxy #160493
83 manager.reactOnUserInput()
Aplicabilidad
Hay decenas de formas de utilizar el patrón Proxy. Repasemos
los usos más populares.
[email protected] (#160493)
262 Patrones estructurales / Proxy #160493
[email protected] (#160493)
263 Patrones estructurales / Proxy #160493
Cómo implementarlo
1. Si no hay una interfaz de servicio preexistente, crea una para
que los objetos de proxy y de servicio sean intercambiables.
No siempre resulta posible extraer la interfaz de la clase ser-
vicio, porque tienes que cambiar todos los clientes del servi-
cio para utilizar esa interfaz. El plan B consiste en convertir el
proxy en una subclase de la clase servicio, de forma que here-
de la interfaz del servicio.
[email protected] (#160493)
264 Patrones estructurales / Proxy #160493
Pros y contras
Puedes controlar el objeto de servicio sin que los clientes
lo sepan.
Puedes gestionar el ciclo de vida del objeto de servicio cuando
a los clientes no les importa.
El proxy funciona incluso si el objeto de servicio no está listo
o no está disponible.
Principio de abierto/cerrado. Puedes introducir nuevos proxies
sin cambiar el servicio o los clientes.
[email protected] (#160493)
265 Patrones estructurales / Proxy #160493
[email protected] (#160493)
266 Patrones de comportamiento #160493
Patrones de
comportamiento
Los patrones de comportamiento tratan con algoritmos y la
asignación de responsabilidades entre objetos.
Chain of
Responsibility
Permite pasar solicitudes a lo largo de una cadena de manejado-
res. Al recibir una solicitud, cada manejador decide si la procesa
o si la pasa al siguiente manejador de la cadena.
Command
Convierte una solicitud en un objeto independiente que contiene
toda la información sobre la solicitud. Esta transformación te per-
mite parametrizar los métodos con diferentes solicitudes, retrasar
o poner en cola la ejecución de una solicitud y soportar operacio-
nes que no se pueden realizar.
[email protected] (#160493)
267 Patrones de comportamiento #160493
Iterator
Permite recorrer elementos de una colección sin exponer su re-
presentación subyacente (lista, pila, árbol, etc.).
Mediator
Permite reducir las dependencias caóticas entre objetos. El pa-
trón restringe las comunicaciones directas entre los objetos, for-
zándolos a colaborar únicamente a través de un objeto mediador.
Memento
Permite guardar y restaurar el estado previo de un objeto sin re-
velar los detalles de su implementación.
[email protected] (#160493)
268 Patrones de comportamiento #160493
Observer
Permite definir un mecanismo de suscripción para notificar a va-
rios objetos sobre cualquier evento que le suceda al objeto que
están observando.
State
Permite a un objeto alterar su comportamiento cuando su estado
interno cambia. Parece como si el objeto cambiara su clase.
Strategy
Permite definir una familia de algoritmos, colocar cada uno de
ellos en una clase separada y hacer sus objetos intercambiables.
[email protected] (#160493)
269 Patrones de comportamiento #160493
Template
Method
Define el esqueleto de un algoritmo en la superclase pero permi-
te que las subclases sobrescriban pasos del algoritmo sin cam-
biar su estructura.
Visitor
Permite separar algoritmos de los objetos sobre los que operan.
[email protected] (#160493)
270 Patrones de comportamiento / Chain of Responsibility #160493
CHAIN OF
RESPONSIBILITY
También llamado: Cadena de responsabilidad, CoR,
Chain of Command
[email protected] (#160493)
271 Patrones de comportamiento / Chain of Responsibility #160493
Problema
Imagina que estás trabajando en un sistema de pedidos online.
Quieres restringir el acceso al sistema de forma que únicamen-
te los usuarios autenticados puedan generar pedidos. Además,
los usuarios que tengan permisos administrativos deben tener
pleno acceso a todos los pedidos.
[email protected] (#160493)
272 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
273 Patrones de comportamiento / Chain of Responsibility #160493
Solución
Al igual que muchos otros patrones de diseño de comporta-
miento, el Chain of Responsibility se basa en transformar co-
mportamientos particulares en objetos autónomos llamados
manejadores. En nuestro caso, cada comprobación debe pone-
rse dentro de su propia clase con un único método que reali-
ce la comprobación. La solicitud, junto con su información, se
pasa a este método como argumento.
[email protected] (#160493)
274 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
275 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
276 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
277 Patrones de comportamiento / Chain of Responsibility #160493
Estructura
[email protected] (#160493)
278 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
279 Patrones de comportamiento / Chain of Responsibility #160493
Pseudocódigo
En este ejemplo, el patrón Chain of Responsibility es respon-
sable de mostrar información de ayuda contextual para eleme-
ntos GUI activos.
Las clases GUI se crean con el patrón Composite. Cada elemento se vincula
a su elemento contenedor. En cualquier momento puedes crear una cadena
de elementos que comience con el propio elemento y recorra todos los
elementos contenedores.
[email protected] (#160493)
280 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
281 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
282 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
283 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
284 Patrones de comportamiento / Chain of Responsibility #160493
Aplicabilidad
Utiliza el patrón Chain of Responsibility cuando tu programa
deba procesar distintos tipos de solicitudes de varias maneras,
pero los tipos exactos de solicitudes y sus secuencias no se co-
nozcan de antemano.
[email protected] (#160493)
285 Patrones de comportamiento / Chain of Responsibility #160493
Cómo implementarlo
1. Declara la interfaz manejadora y describe la firma de un méto-
do para manejar solicitudes.
[email protected] (#160493)
286 Patrones de comportamiento / Chain of Responsibility #160493
◦ Si procesa la solicitud.
Pros y contras
Puedes controlar el orden de control de solicitudes.
[email protected] (#160493)
287 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
288 Patrones de comportamiento / Chain of Responsibility #160493
[email protected] (#160493)
289 Patrones de comportamiento / Command #160493
COMMAND
También llamado: Comando, Orden, Action, Transaction
[email protected] (#160493)
290 Patrones de comportamiento / Command #160493
Problema
Imagina que estás trabajando en una nueva aplicación de edi-
ción de texto. Tu tarea actual consiste en crear una barra de
herramientas con unos cuantos botones para varias operacio-
nes del editor. Creaste una clase Botón muy limpia que puede
utilizarse para los botones de la barra de herramientas y tam-
bién para botones genéricos en diversos diálogos.
[email protected] (#160493)
291 Patrones de comportamiento / Command #160493
[email protected] (#160493)
292 Patrones de comportamiento / Command #160493
Solución
El buen diseño de software a menudo se basa en el principio
de separación de responsabilidades, lo que suele tener como
resultado la división de la aplicación en capas. El ejemplo más
habitual es tener una capa para la interfaz gráfica de usua-
rio (GUI) y otra capa para la lógica de negocio. La capa GUI
es responsable de representar una bonita imagen en pantalla,
capturar entradas y mostrar resultados de lo que el usuario y
la aplicación están haciendo. Sin embargo, cuando se trata de
hacer algo importante, como calcular la trayectoria de la luna
o componer un informe anual, la capa GUI delega el trabajo a
la capa subyacente de la lógica de negocio.
[email protected] (#160493)
293 Patrones de comportamiento / Command #160493
[email protected] (#160493)
294 Patrones de comportamiento / Command #160493
Puede que hayas observado que falta una pieza del rompeca-
bezas, que son los parámetros de la solicitud. Un objeto GUI
puede haber proporcionado al objeto de la capa de negocio al-
gunos parámetros. Ya que el método de ejecución del coma-
ndo no tiene parámetros, ¿cómo pasaremos los detalles de la
solicitud al receptor? Resulta que el comando debe estar pre-
configurado con esta información o ser capaz de conseguirla
por su cuenta.
[email protected] (#160493)
295 Patrones de comportamiento / Command #160493
[email protected] (#160493)
296 Patrones de comportamiento / Command #160493
[email protected] (#160493)
297 Patrones de comportamiento / Command #160493
Estructura
[email protected] (#160493)
298 Patrones de comportamiento / Command #160493
[email protected] (#160493)
299 Patrones de comportamiento / Command #160493
Pseudocódigo
En este ejemplo, el patrón Command ayuda a rastrear el histo-
rial de operaciones ejecutadas y hace posible revertir una ope-
ración si es necesario.
[email protected] (#160493)
300 Patrones de comportamiento / Command #160493
[email protected] (#160493)
301 Patrones de comportamiento / Command #160493
18 editor.text = backup
19
20 // El método de ejecución se declara abstracto para forzar a
21 // todos los comandos concretos a proporcionar sus propias
22 // implementaciones. El método debe devolver verdadero o
23 // falso dependiendo de si el comando cambia el estado del
24 // editor.
25 abstract method execute()
26
27
28 // Los comandos concretos van aquí.
29 class CopyCommand extends Command is
30 // El comando copiar no se guarda en el historial ya que no
31 // cambia el estado del editor.
32 method execute() is
33 app.clipboard = editor.getSelection()
34 return false
35
36 class CutCommand extends Command is
37 // El comando cortar no cambia el estado del editor, por lo
38 // que debe guardarse en el historial. Y se guardará siempre
39 // y cuando el método devuelva verdadero.
40 method execute() is
41 saveBackup()
42 app.clipboard = editor.getSelection()
43 editor.deleteSelection()
44 return true
45
46 class PasteCommand extends Command is
47 method execute() is
48 saveBackup()
49 editor.replaceSelection(app.clipboard)
[email protected] (#160493)
302 Patrones de comportamiento / Command #160493
50 return true
51
52 // La operación deshacer también es un comando.
53 class UndoCommand extends Command is
54 method execute() is
55 app.undo()
56 return false
57
58
59 // El historial global de comandos tan solo es una pila.
60 class CommandHistory is
61 private field history: array of Command
62
63 // El último dentro...
64 method push(c: Command) is
65 // Empuja el comando al final de la matriz del
66 // historial.
67
68 // ...el primero fuera.
69 method pop():Command is
70 // Obtiene el comando más reciente del historial.
71
72
73 // La clase editora tiene operaciones reales de edición de
74 // texto. Juega el papel de un receptor: todos los comandos
75 // acaban delegando la ejecución a los métodos del editor.
76 class Editor is
77 field text: string
78
79 method getSelection() is
80 // Devuelve el texto seleccionado.
81
[email protected] (#160493)
303 Patrones de comportamiento / Command #160493
82 method deleteSelection() is
83 // Borra el texto seleccionado.
84
85 method replaceSelection(text) is
86 // Inserta los contenidos del portapapeles en la
87 // posición actual.
88
89
90 // La clase Aplicación establece relaciones entre objetos. Actúa
91 // como un emisor: cuando algo debe hacerse, crea un objeto de
92 // comando y lo ejecuta.
93 class Application is
94 field clipboard: string
95 field editors: array of Editors
96 field activeEditor: Editor
97 field history: CommandHistory
98
99 // El código que asigna comandos a objetos UI puede tener
100 // este aspecto.
101 method createUI() is
102 // ...
103 copy = function
function() { executeCommand(
104 new CopyCommand(this
this, activeEditor)) }
105 copyButton.setCommand(copy)
106 shortcuts.onKeyPress("Ctrl+C", copy)
107
108 cut = function
function() { executeCommand(
109 new CutCommand(this
this, activeEditor)) }
110 cutButton.setCommand(cut)
111 shortcuts.onKeyPress("Ctrl+X", cut)
112
113 paste = function
function() { executeCommand(
[email protected] (#160493)
304 Patrones de comportamiento / Command #160493
Aplicabilidad
Utiliza el patrón Command cuando quieras parametrizar obje-
tos con operaciones.
[email protected] (#160493)
305 Patrones de comportamiento / Command #160493
[email protected] (#160493)
306 Patrones de comportamiento / Command #160493
Cómo implementarlo
1. Declara la interfaz de comando con un único método de
ejecución.
[email protected] (#160493)
307 Patrones de comportamiento / Command #160493
◦ Crear receptores.
Pros y contras
Principio de responsabilidad única. Puedes desacoplar las clases
que invocan operaciones de las que realizan esas operaciones.
Principio de abierto/cerrado. Puedes introducir nuevos coma-
ndos en la aplicación sin descomponer el código cliente
existente.
Puedes implementar deshacer/rehacer.
[email protected] (#160493)
308 Patrones de comportamiento / Command #160493
[email protected] (#160493)
309 Patrones de comportamiento / Command #160493
[email protected] (#160493)
310 Patrones de comportamiento / Iterator #160493
ITERATOR
También llamado: Iterador
[email protected] (#160493)
311 Patrones de comportamiento / Iterator #160493
Problema
Las colecciones son de los tipos de datos más utilizados en
programación. Sin embargo, una colección tan solo es un con-
tenedor para un grupo de objetos.
[email protected] (#160493)
312 Patrones de comportamiento / Iterator #160493
Por otro lado, el código cliente que debe funcionar con varias
colecciones puede no saber cómo éstas almacenan sus eleme-
ntos. No obstante, ya que todas las colecciones proporcionan
formas diferentes de acceder a sus elementos, no tienes otra
opción más que acoplar tu código a las clases de la colección
específica.
Solución
La idea central del patrón Iterator es extraer el comportamie-
nto de recorrido de una colección y colocarlo en un objeto in-
dependiente llamado iterador.
[email protected] (#160493)
313 Patrones de comportamiento / Iterator #160493
[email protected] (#160493)
314 Patrones de comportamiento / Iterator #160493
Planeas visitar Roma por unos días y ver todas sus atraccio-
nes y puntos de interés. Pero, una vez allí, podrías perder
mucho tiempo dando vueltas, incapaz de encontrar siquiera el
Coliseo.
[email protected] (#160493)
315 Patrones de comportamiento / Iterator #160493
[email protected] (#160493)
316 Patrones de comportamiento / Iterator #160493
Estructura
[email protected] (#160493)
317 Patrones de comportamiento / Iterator #160493
Pseudocódigo
En este ejemplo, el patrón Iterator se utiliza para recorrer un
tipo especial de colección que encapsula el acceso al grafo so-
cial de Facebook. La colección proporciona varios iteradores
que recorren perfiles de distintas formas.
[email protected] (#160493)
318 Patrones de comportamiento / Iterator #160493
[email protected] (#160493)
319 Patrones de comportamiento / Iterator #160493
[email protected] (#160493)
320 Patrones de comportamiento / Iterator #160493
26
27
28 // La clase iteradora concreta.
29 class FacebookIterator implements ProfileIterator is
30 // El iterador necesita una referencia a la colección que
31 // recorre.
32 private field facebook: Facebook
33 private field profileId, type: string
34
35 // Un objeto iterador recorre la colección
36 // independientemente de otro iterador, por eso debe
37 // almacenar el estado de iteración.
38 private field currentPosition
39 private field cache: array of Profile
40
41 constructor FacebookIterator(facebook, profileId, type) is
42 this
this.facebook = facebook
43 this
this.profileId = profileId
44 this
this.type = type
45
46 private method lazyInit() is
47 if (cache == null
null)
48 cache = facebook.socialGraphRequest(profileId, type)
49
50 // Cada clase iteradora concreta tiene su propia
51 // implementación de la interfaz iteradora común.
52 method getNext() is
53 if (hasMore())
54 result = cache[currentPosition]
55 currentPosition++
56 return result
57
[email protected] (#160493)
321 Patrones de comportamiento / Iterator #160493
58 method hasMore() is
59 lazyInit()
60 return currentPosition < cache.length
61
62
63 // Aquí tienes otro truco útil: puedes pasar un iterador a una
64 // clase cliente en lugar de darle acceso a una colección
65 // completa. De esta forma, no expones la colección al cliente.
66 //
67 // Y hay otra ventaja: puedes cambiar la forma en la que el
68 // cliente trabaja con la colección durante el tiempo de
69 // ejecución pasándole un iterador diferente. Esto es posible
70 // porque el código cliente no está acoplado a clases iteradoras
71 // concretas.
72 class SocialSpammer is
73 method send(iterator: ProfileIterator, message: string) is
74 while (iterator.hasMore())
75 profile = iterator.getNext()
76 System.sendEmail(profile.getEmail(), message)
77
78
79 // La clase Aplicación configura colecciones e iteradores y
80 // después los pasa al código cliente.
81 class Application is
82 field network: SocialNetwork
83 field spammer: SocialSpammer
84
85 method config() is
86 if working with Facebook
87 this
this.network = new Facebook()
88 if working with LinkedIn
89 this
this.network = new LinkedIn()
[email protected] (#160493)
322 Patrones de comportamiento / Iterator #160493
90 this
this.spammer = new SocialSpammer()
91
92 method sendSpamToFriends(profile) is
93 iterator = network.createFriendsIterator(profile.getId())
94 spammer.send(iterator, "Very important message")
95
96 method sendSpamToCoworkers(profile) is
97 iterator = network.createCoworkersIterator(profile.getId())
98 spammer.send(iterator, "Very important message")
Aplicabilidad
Utiliza el patrón Iterator cuando tu colección tenga una estruc-
tura de datos compleja a nivel interno, pero quieras ocultar su
complejidad a los clientes (ya sea por conveniencia o por razo-
nes de seguridad).
[email protected] (#160493)
323 Patrones de comportamiento / Iterator #160493
Cómo implementarlo
1. Declara la interfaz iteradora. Como mínimo, debe tener un
método para extraer el siguiente elemento de una colección.
Por conveniencia, puedes añadir un par de métodos distintos,
como para extraer el elemento previo, localizar la posición ac-
tual o comprobar el final de la iteración.
[email protected] (#160493)
324 Patrones de comportamiento / Iterator #160493
Pros y contras
Principio de responsabilidad única. Puedes limpiar el código
cliente y las colecciones extrayendo algoritmos de recorrido
voluminosos y colocándolos en clases independientes.
Principio de abierto/cerrado. Puedes implementar nuevos tipos
de colecciones e iteradores y pasarlos al código existente sin
descomponer nada.
Puedes recorrer la misma colección en paralelo porque cada
objeto iterador contiene su propio estado de iteración.
[email protected] (#160493)
325 Patrones de comportamiento / Iterator #160493
• Puedes utilizar Visitor junto con Iterator para recorrer una es-
tructura de datos compleja y ejecutar alguna operación sobre
sus elementos, incluso aunque todos tengan clases distintas.
[email protected] (#160493)
326 Patrones de comportamiento / Mediator #160493
MEDIATOR
También llamado: Mediador, Intermediary, Controller
[email protected] (#160493)
327 Patrones de comportamiento / Mediator #160493
Problema
Digamos que tienes un diálogo para crear y editar perfiles de
cliente. Consiste en varios controles de formulario, como cam-
pos de texto, casillas, botones, etc.
[email protected] (#160493)
328 Patrones de comportamiento / Mediator #160493
Los elementos pueden tener muchas relaciones con otros elementos. Por
eso, los cambios en algunos elementos pueden afectar a los demás.
Solución
El patrón Mediator sugiere que detengas toda comunicación
directa entre los componentes que quieres hacer independien-
tes entre sí. En lugar de ello, estos componentes deberán cola-
borar indirectamente, invocando un objeto mediador especial
que redireccione las llamadas a los componentes adecuados.
Como resultado, los componentes dependen únicamente de
una sola clase mediadora, en lugar de estar acoplados a dece-
nas de sus colegas.
[email protected] (#160493)
329 Patrones de comportamiento / Mediator #160493
[email protected] (#160493)
330 Patrones de comportamiento / Mediator #160493
Los pilotos de los aviones que llegan o salen del área de con-
trol del aeropuerto no se comunican directamente entre sí. En
lugar de eso, hablan con un controlador de tráfico aéreo, que
está sentado en una torre alta cerca de la pista de aterrizaje.
[email protected] (#160493)
331 Patrones de comportamiento / Mediator #160493
Estructura
[email protected] (#160493)
332 Patrones de comportamiento / Mediator #160493
[email protected] (#160493)
333 Patrones de comportamiento / Mediator #160493
Pseudocódigo
En este ejemplo, el patrón Mediator te ayuda a eliminar depe-
ndencias mutuas entre varias clases UI: botones, casillas y eti-
quetas de texto.
[email protected] (#160493)
334 Patrones de comportamiento / Mediator #160493
[email protected] (#160493)
335 Patrones de comportamiento / Mediator #160493
[email protected] (#160493)
336 Patrones de comportamiento / Mediator #160493
[email protected] (#160493)
337 Patrones de comportamiento / Mediator #160493
Aplicabilidad
Utiliza el patrón Mediator cuando resulte difícil cambiar algu-
nas de las clases porque están fuertemente acopladas a un pu-
ñado de otras clases.
[email protected] (#160493)
338 Patrones de comportamiento / Mediator #160493
Cómo implementarlo
1. Identifica un grupo de clases fuertemente acopladas que se
beneficiarían de ser más independientes (p. ej., para un mante-
nimiento más sencillo o una reutilización más simple de esas
clases).
[email protected] (#160493)
339 Patrones de comportamiento / Mediator #160493
Pros y contras
• Principio de responsabilidad única. Puedes extraer las comu-
nicaciones entre varios componentes dentro de un único sitio,
haciéndolo más fácil de comprender y mantener.
[email protected] (#160493)
340 Patrones de comportamiento / Memento #160493
MEMENTO
También llamado: Recuerdo, Instantánea, Snapshot
[email protected] (#160493)
341 Patrones de comportamiento / Memento #160493
Problema
Imagina que estás creando una aplicación de edición de texto.
Además de editar texto, tu programa puede formatearlo, asi
como insertar imágenes en línea, etc.
[email protected] (#160493)
342 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
343 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
344 Patrones de comportamiento / Memento #160493
Solución
Todos los problemas que hemos experimentado han sido pro-
vocados por una encapsulación fragmentada. Algunos objetos
intentan hacer más de lo que deben. Para recopilar los datos
necesarios para realizar una acción, invaden el espacio privado
de otros objetos en lugar de permitir a esos objetos realizar la
propia acción.
[email protected] (#160493)
345 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
346 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
347 Patrones de comportamiento / Memento #160493
Estructura
Implementación basada en clases anidadas
[email protected] (#160493)
348 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
349 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
350 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
351 Patrones de comportamiento / Memento #160493
Pseudocódigo
Este ejemplo utiliza el patrón Memento junto al patrón Co-
mmand para almacenar instantáneas del estado complejo del
editor de texto y restaurar un estado previo a partir de estas
instantáneas cuando sea necesario.
[email protected] (#160493)
352 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
353 Patrones de comportamiento / Memento #160493
24
25 // La clase memento almacena el estado pasado del editor.
26 class Snapshot is
27 private field editor: Editor
28 private field text, curX, curY, selectionWidth
29
30 constructor Snapshot(editor, text, curX, curY, selectionWidth) is
31 this
this.editor = editor
32 this
this.text = text
33 this
this.curX = x
34 this
this.curY = y
35 this
this.selectionWidth = selectionWidth
36
37 // En cierto punto, puede restaurarse un estado previo del
38 // editor utilizando un objeto memento.
39 method restore() is
40 editor.setText(text)
41 editor.setCursor(curX, curY)
42 editor.setSelectionWidth(selectionWidth)
43
44 // Un objeto de comando puede actuar como cuidador. En este
45 // caso, el comando obtiene un memento justo antes de cambiar el
46 // estado del originador. Cuando se solicita deshacer, restaura
47 // el estado del originador a partir del memento.
48 class Command is
49 private field backup: Snapshot
50
51 method makeBackup() is
52 backup = editor.createSnapshot()
53
54 method undo() is
55 if (backup != null
null)
[email protected] (#160493)
354 Patrones de comportamiento / Memento #160493
56 backup.restore()
57 // ...
Aplicabilidad
Utiliza el patrón Memento cuando quieras producir instantá-
neas del estado del objeto para poder restaurar un estado pre-
vio del objeto.
[email protected] (#160493)
355 Patrones de comportamiento / Memento #160493
Cómo implementarlo
1. Determina qué clase jugará el papel de la originadora. Es im-
portante saber si el programa utiliza un objeto central de este
tipo o varios más pequeños.
El tipo de retorno del método debe ser del mismo que la in-
terfaz que extrajiste en el paso anterior (asumiendo que lo hi-
[email protected] (#160493)
356 Patrones de comportamiento / Memento #160493
Pros y contras
Puedes producir instantáneas del estado del objeto sin violar
su encapsulación.
[email protected] (#160493)
357 Patrones de comportamiento / Memento #160493
[email protected] (#160493)
358 Patrones de comportamiento / Observer #160493
OBSERVER
También llamado: Observador, Publicación-Suscripción,
Modelo-patrón, Event-Subscriber, Listener
[email protected] (#160493)
359 Patrones de comportamiento / Observer #160493
Problema
Imagina que tienes dos tipos de objetos: un objeto Cliente y
un objeto Tienda . El cliente está muy interesado en una marca
particular de producto (digamos, un nuevo modelo de iPhone)
que estará disponible en la tienda muy pronto.
[email protected] (#160493)
360 Patrones de comportamiento / Observer #160493
Solución
El objeto que tiene un estado interesante suele denominarse suje-
to, pero, como también va a notificar a otros objetos los cambios
en su estado, le llamaremos notificador (en ocasiones también lla-
mado publicador). El resto de los objetos que quieren conocer los
cambios en el estado del notificador, se denominan suscriptores.
[email protected] (#160493)
361 Patrones de comportamiento / Observer #160493
[email protected] (#160493)
362 Patrones de comportamiento / Observer #160493
[email protected] (#160493)
363 Patrones de comportamiento / Observer #160493
Estructura
[email protected] (#160493)
364 Patrones de comportamiento / Observer #160493
Pseudocódigo
En este ejemplo, el patrón Observer permite al objeto editor
de texto notificar a otros objetos tipo servicio sobre los cam-
bios en su estado.
[email protected] (#160493)
365 Patrones de comportamiento / Observer #160493
[email protected] (#160493)
366 Patrones de comportamiento / Observer #160493
[email protected] (#160493)
367 Patrones de comportamiento / Observer #160493
28
29 // Los métodos de la lógica de negocio pueden notificar los
30 // cambios a los suscriptores.
31 method openFile(path) is
32 this
this.file = new File(path)
33 events.notify("open", file.name)
34
35 method saveFile() is
36 file.write()
37 events.notify("save", file.name)
38
39 // ...
40
41
42 // Aquí está la interfaz suscriptora. Si tu lenguaje de
43 // programación soporta tipos funcionales, puedes sustituir toda
44 // la jerarquía suscriptora por un grupo de funciones.
45
46
47 interface EventListener is
48 method update(filename)
49
50 // Los suscriptores concretos reaccionan a las actualizaciones
51 // emitidas por el notificador al que están unidos.
52 class LoggingListener implements EventListener is
53 private field log: File
54 private field message: string
55
56 constructor LoggingListener(log_filename, message) is
57 this
this.log = new File(log_filename)
58 this
this.message = message
59
[email protected] (#160493)
368 Patrones de comportamiento / Observer #160493
60 method update(filename) is
61 log.write(replace('%s',filename,message))
62
63 class EmailAlertsListener implements EventListener is
64 private field email: string
65 private field message: string
66
67 constructor EmailAlertsListener(email, message) is
68 this
this.email = email
69 this
this.message = message
70
71 method update(filename) is
72 system.email(email, replace('%s',filename,message))
73
74
75 // Una aplicación puede configurar notificadores y suscriptores
76 // durante el tiempo de ejecución.
77 class Application is
78 method config() is
79 editor = new Editor()
80
81 logger = new LoggingListener(
82 "/path/to/log.txt",
83 "Someone has opened the file: %s")
84 editor.events.subscribe("open", logger)
85
86 emailAlerts = new EmailAlertsListener(
87 "[email protected]",
88 "Someone has changed the file: %s")
89 editor.events.subscribe("save", emailAlerts)
[email protected] (#160493)
369 Patrones de comportamiento / Observer #160493
Aplicabilidad
Utiliza el patrón Observer cuando los cambios en el estado de
un objeto puedan necesitar cambiar otros objetos y el grupo
de objetos sea desconocido de antemano o cambie dinámica-
mente.
[email protected] (#160493)
370 Patrones de comportamiento / Observer #160493
Cómo implementarlo
1. Repasa tu lógica de negocio e intenta dividirla en dos partes:
la funcionalidad central, independiente del resto de código,
actuará como notificador; el resto se convertirá en un grupo de
clases suscriptoras.
[email protected] (#160493)
371 Patrones de comportamiento / Observer #160493
Pros y contras
Principio de abierto/cerrado. Puedes introducir nuevas clases
suscriptoras sin tener que cambiar el código de la notificadora
(y viceversa si hay una interfaz notificadora).
Puedes establecer relaciones entre objetos durante el tiempo
de ejecución.
[email protected] (#160493)
372 Patrones de comportamiento / Observer #160493
[email protected] (#160493)
373 Patrones de comportamiento / Observer #160493
[email protected] (#160493)
374 Patrones de comportamiento / State #160493
STATE
También llamado: Estado
[email protected] (#160493)
375 Patrones de comportamiento / State #160493
Problema
El patrón State está estrechamente relacionado con el conce-
1
pto de la Máquina de estados finitos .
[email protected] (#160493)
376 Patrones de comportamiento / State #160493
[email protected] (#160493)
377 Patrones de comportamiento / State #160493
1 class Document is
2 field state: string
3 // ...
4 method publish() is
5 switch (state)
6 "draft":
7 state = "moderation"
8 break
9 "moderation":
10 if (currentUser.role == "admin")
11 state = "published"
12 break
13 "published":
14 // No hacer nada.
15 break
16 // ...
[email protected] (#160493)
378 Patrones de comportamiento / State #160493
Solución
El patrón State sugiere que crees nuevas clases para todos los
estados posibles de un objeto y extraigas todos los comporta-
mientos específicos del estado para colocarlos dentro de esas
clases.
[email protected] (#160493)
379 Patrones de comportamiento / State #160493
[email protected] (#160493)
380 Patrones de comportamiento / State #160493
Estructura
[email protected] (#160493)
381 Patrones de comportamiento / State #160493
[email protected] (#160493)
382 Patrones de comportamiento / State #160493
Pseudocódigo
En este ejemplo, el patrón State permite a los mismos contro-
les del reproductor de medios comportarse de forma diferente,
dependiendo del estado actual de reproducción.
[email protected] (#160493)
383 Patrones de comportamiento / State #160493
[email protected] (#160493)
384 Patrones de comportamiento / State #160493
33 method clickNext() is
34 state.clickNext()
35 method clickPrevious() is
36 state.clickPrevious()
37
38 // Un estado puede invocar algunos métodos del servicio en
39 // el contexto.
40 method startPlayback() is
41 // ...
42 method stopPlayback() is
43 // ...
44 method nextSong() is
45 // ...
46 method previousSong() is
47 // ...
48 method fastForward(time) is
49 // ...
50 method rewind(time) is
51 // ...
52
53
54 // La clase estado base declara métodos que todos los estados
55 // concretos deben implementar, y también proporciona una
56 // referencia inversa al objeto de contexto asociado con el
57 // estado. Los estados pueden utilizar la referencia inversa
58 // para dirigir el contexto a otro estado.
59 abstract class State is
60 protected field player: AudioPlayer
61
62 // El contexto se pasa a sí mismo a través del constructor
63 // del estado. Esto puede ayudar al estado a extraer
64 // información de contexto útil si la necesita.
[email protected] (#160493)
385 Patrones de comportamiento / State #160493
65 constructor State(player) is
66 this
this.player = player
67
68 abstract method clickLock()
69 abstract method clickPlay()
70 abstract method clickNext()
71 abstract method clickPrevious()
72
73
74 // Los estados concretos implementan varios comportamientos
75 // asociados a un estado del contexto.
76 class LockedState extends State is
77
78 // Cuando desbloqueas a un jugador bloqueado, puede asumir
79 // uno de dos estados.
80 method clickLock() is
81 if (player.playing)
82 player.changeState(new
new PlayingState(player))
83 else
84 player.changeState(new
new ReadyState(player))
85
86 method clickPlay() is
87 // Bloqueado, no hace nada.
88
89 method clickNext() is
90 // Bloqueado, no hace nada.
91
92 method clickPrevious() is
93 // Bloqueado, no hace nada.
94
95 // También pueden disparar transiciones de estado en el
96 // contexto.
[email protected] (#160493)
386 Patrones de comportamiento / State #160493
[email protected] (#160493)
387 Patrones de comportamiento / State #160493
129 else
130 player.rewind(5)
Aplicabilidad
Utiliza el patrón State cuando tengas un objeto que se compo-
rta de forma diferente dependiendo de su estado actual, el nú-
mero de estados sea enorme y el código específico del estado
cambie con frecuencia.
[email protected] (#160493)
388 Patrones de comportamiento / State #160493
Cómo implementarlo
1. Decide qué clase actuará como contexto. Puede ser una clase
existente que ya tiene el código dependiente del estado, o una
nueva clase, si el código específico del estado está distribuido
a lo largo de varias clases.
[email protected] (#160493)
389 Patrones de comportamiento / State #160493
Pros y contras
Principio de responsabilidad única. Organiza el código relacio-
nado con estados particulares en clases separadas.
Principio de abierto/cerrado. Introduce nuevos estados sin cam-
biar clases de estado existentes o la clase contexto.
[email protected] (#160493)
390 Patrones de comportamiento / State #160493
[email protected] (#160493)
391 Patrones de comportamiento / Strategy #160493
STRATEGY
También llamado: Estrategia
[email protected] (#160493)
392 Patrones de comportamiento / Strategy #160493
Problema
Un día decidiste crear una aplicación de navegación para via-
jeros ocasionales. La aplicación giraba alrededor de un bonito
mapa que ayudaba a los usuarios a orientarse rápidamente en
cualquier ciudad.
[email protected] (#160493)
393 Patrones de comportamiento / Strategy #160493
[email protected] (#160493)
394 Patrones de comportamiento / Strategy #160493
Solución
El patrón Strategy sugiere que tomes esa clase que hace algo
específico de muchas formas diferentes y extraigas todos esos
algoritmos para colocarlos en clases separadas llamadas estra-
tegias.
[email protected] (#160493)
395 Patrones de comportamiento / Strategy #160493
[email protected] (#160493)
396 Patrones de comportamiento / Strategy #160493
[email protected] (#160493)
397 Patrones de comportamiento / Strategy #160493
Estructura
[email protected] (#160493)
398 Patrones de comportamiento / Strategy #160493
Pseudocódigo
En este ejemplo, el contexto utiliza varias estrategias para eje-
cutar diversas operaciones aritméticas.
[email protected] (#160493)
399 Patrones de comportamiento / Strategy #160493
16 method execute(a, b) is
17 return a - b
18
19 class ConcreteStrategyMultiply implements Strategy is
20 method execute(a, b) is
21 return a * b
22
23 // El contexto define la interfaz de interés para los clientes.
24 class Context is
25 // El contexto mantiene una referencia a uno de los objetos
26 // de estrategia. El contexto no conoce la clase concreta de
27 // una estrategia. Debe trabajar con todas las estrategias a
28 // través de la interfaz estrategia.
29 private strategy: Strategy
30
31 // Normalmente, el contexto acepta una estrategia a través
32 // del constructor y también proporciona un setter
33 // (modificador) para poder cambiar la estrategia durante el
34 // tiempo de ejecución.
35 method setStrategy(Strategy strategy) is
36 this
this.strategy = strategy
37
38 // El contexto delega parte del trabajo al objeto de
39 // estrategia en lugar de implementar varias versiones del
40 // algoritmo por su cuenta.
41 method executeStrategy(int a, int b) is
42 return strategy.execute(a, b)
43
44
45 // El código cliente elige una estrategia concreta y la pasa al
46 // contexto. El cliente debe conocer las diferencias entre
47 // estrategias para elegir la mejor opción.
[email protected] (#160493)
400 Patrones de comportamiento / Strategy #160493
48 class ExampleApplication is
49 method main() is
50 Create context object.
51
52 Read first number.
53 Read last number.
54 Read the desired action from user input.
55
56 if (action == addition) then
57 context.setStrategy(new
new ConcreteStrategyAdd())
58
59 if (action == subtraction) then
60 context.setStrategy(new
new ConcreteStrategySubtract())
61
62 if (action == multiplication) then
63 context.setStrategy(new
new ConcreteStrategyMultiply())
64
65 result = context.executeStrategy(First number, Second number)
66
67 Print result.
Aplicabilidad
Utiliza el patrón Strategy cuando quieras utiliza distintas va-
riantes de un algoritmo dentro de un objeto y poder cambiar
de un algoritmo a otro durante el tiempo de ejecución.
[email protected] (#160493)
401 Patrones de comportamiento / Strategy #160493
[email protected] (#160493)
402 Patrones de comportamiento / Strategy #160493
Cómo implementarlo
1. En la clase contexto, identifica un algoritmo que tienda a sufrir
cambios frecuentes. También puede ser un enorme condicio-
nal que seleccione y ejecute una variante del mismo algoritmo
durante el tiempo de ejecución.
[email protected] (#160493)
403 Patrones de comportamiento / Strategy #160493
Pros y contras
Puedes intercambiar algoritmos usados dentro de un objeto
durante el tiempo de ejecución.
Puedes aislar los detalles de implementación de un algoritmo
del código que lo utiliza.
Puedes sustituir la herencia por composición.
[email protected] (#160493)
404 Patrones de comportamiento / Strategy #160493
[email protected] (#160493)
405 Patrones de comportamiento / Strategy #160493
[email protected] (#160493)
406 Patrones de comportamiento / Template Method #160493
TEMPLATE METHOD
También llamado: Método plantilla
[email protected] (#160493)
407 Patrones de comportamiento / Template Method #160493
Problema
Imagina que estás creando una aplicación de minería de datos
que analiza documentos corporativos. Los usuarios suben a la
aplicación documentos en varios formatos (PDF, DOC, CSV) y
ésta intenta extraer la información relevante de estos docume-
ntos en un formato uniforme.
[email protected] (#160493)
408 Patrones de comportamiento / Template Method #160493
Solución
El patrón Template Method sugiere que dividas un algoritmo
en una serie de pasos, conviertas estos pasos en métodos y
coloques una serie de llamadas a esos métodos dentro de un
único método plantilla. Los pasos pueden ser abstractos , o co-
ntar con una implementación por defecto. Para utilizar el algo-
ritmo, el cliente debe aportar su propia subclase, implementar
todos los pasos abstractos y sobrescribir algunos de los opcio-
nales si es necesario (pero no el propio método plantilla).
[email protected] (#160493)
409 Patrones de comportamiento / Template Method #160493
[email protected] (#160493)
410 Patrones de comportamiento / Template Method #160493
[email protected] (#160493)
411 Patrones de comportamiento / Template Method #160493
[email protected] (#160493)
412 Patrones de comportamiento / Template Method #160493
Estructura
[email protected] (#160493)
413 Patrones de comportamiento / Template Method #160493
Pseudocódigo
En este ejemplo, el patrón Template Method proporciona un
“esqueleto” para varias ramas de inteligencia artificial (IA) en
un sencillo videojuego de estrategia.
[email protected] (#160493)
414 Patrones de comportamiento / Template Method #160493
[email protected] (#160493)
415 Patrones de comportamiento / Template Method #160493
29 else
30 sendWarriors(enemy.position)
31
32 abstract method sendScouts(position)
33 abstract method sendWarriors(position)
34
35 // Las clases concretas tienen que implementar todas las
36 // operaciones abstractas de la clase base, pero no deben
37 // sobrescribir el propio método plantilla.
38 class OrcsAI extends GameAI is
39 method buildStructures() is
40 if (there are some resources) then
41 // Construye granjas, después cuarteles y después
42 // fortaleza.
43
44 method buildUnits() is
45 if (there are plenty of resources) then
46 if (there are no scouts)
47 // Crea peón y añádelo al grupo de exploradores.
48 else
49 // Crea soldado, añádelo al grupo de guerreros.
50
51 // ...
52
53 method sendScouts(position) is
54 if (scouts.length > 0) then
55 // Envía exploradores a posición.
56
57 method sendWarriors(position) is
58 if (warriors.length > 5) then
59 // Envía guerreros a posición.
60
[email protected] (#160493)
416 Patrones de comportamiento / Template Method #160493
Aplicabilidad
Utiliza el patrón Template Method cuando quieras permitir a
tus clientes que extiendan únicamente pasos particulares de
un algoritmo, pero no todo el algoritmo o su estructura.
[email protected] (#160493)
417 Patrones de comportamiento / Template Method #160493
Cómo implementarlo
1. Analiza el algoritmo objetivo para ver si puedes dividirlo en
pasos. Considera qué pasos son comunes a todas las subclases
y cuáles siempre serán únicos.
[email protected] (#160493)
418 Patrones de comportamiento / Template Method #160493
5. Para cada variación del algoritmo, crea una nueva subclase co-
ncreta. Ésta debe implementar todos los pasos abstractos, pero
también puede sobrescribir algunos de los opcionales.
Pros y contras
Puedes permitir a los clientes que sobrescriban tan solo cier-
tas partes de un algoritmo grande, para que les afecten menos
los cambios que tienen lugar en otras partes del algoritmo.
Puedes colocar el código duplicado dentro de una superclase.
[email protected] (#160493)
419 Patrones de comportamiento / Template Method #160493
[email protected] (#160493)
420 Patrones de comportamiento / Visitor #160493
VISITOR
También llamado: Visitante
[email protected] (#160493)
421 Patrones de comportamiento / Visitor #160493
Problema
Imagina que tu equipo desarrolla una aplicación que funcio-
na con información geográfica estructurada como un enorme
grafo. Cada nodo del grafo puede representar una entidad co-
mpleja, como una ciudad, pero también cosas más específicas,
como industrias, áreas turísticas, etc. Los nodos están conec-
tados con otros si hay un camino entre los objetos reales que
representan. Técnicamente, cada tipo de nodo está represen-
tado por su propia clase, mientras que cada nodo específico es
un objeto.
[email protected] (#160493)
422 Patrones de comportamiento / Visitor #160493
Había otra razón para el rechazo. Era muy probable que, una
vez que se implementara esta función, alguien del departame-
nto de marketing te pidiera que incluyeras la capacidad de ex-
portar a otros formatos, o te pidiera alguna otra cosa extraña.
Esto te forzaría a cambiar de nuevo esas preciadas y frágiles
clases.
[email protected] (#160493)
423 Patrones de comportamiento / Visitor #160493
Solución
El patrón Visitor sugiere que coloques el nuevo comportamie-
nto en una clase separada llamada visitante, en lugar de in-
tentar integrarlo dentro de clases existentes. El objeto que
originalmente tenía que realizar el comportamiento se pasa
ahora a uno de los métodos del visitante como argumento, de
modo que el método accede a toda la información necesaria
contenida dentro del objeto.
[email protected] (#160493)
424 Patrones de comportamiento / Visitor #160493
[email protected] (#160493)
425 Patrones de comportamiento / Visitor #160493
1 // Código cliente
2 foreach (Node node in graph)
3 node.accept(exportVisitor)
4
5 // Ciudad
6 class City is
7 method accept(Visitor v) is
8 v.doForCity(this
this)
9 // ...
10
11 // Industria
12 class Industry is
13 method accept(Visitor v) is
14 v.doForIndustry(this
this)
15 // ...
[email protected] (#160493)
426 Patrones de comportamiento / Visitor #160493
[email protected] (#160493)
427 Patrones de comportamiento / Visitor #160493
Estructura
[email protected] (#160493)
428 Patrones de comportamiento / Visitor #160493
Pseudocódigo
En este ejemplo, el patrón Visitor añade soporte de exporta-
ción XML a la jerarquía de clases de formas geométricas.
[email protected] (#160493)
429 Patrones de comportamiento / Visitor #160493
[email protected] (#160493)
430 Patrones de comportamiento / Visitor #160493
12 // ...
13
14 // Observa que invocamos `visitDot`, que coincide con el
15 // nombre de la clase actual. De esta forma, hacemos saber
16 // al visitante la clase del elemento con el que trabaja.
17 method accept(v: Visitor) is
18 v.visitDot(this
this)
19
20 class Circle implements Shape is
21 // ...
22 method accept(v: Visitor) is
23 v.visitCircle(this
this)
24
25 class Rectangle implements Shape is
26 // ...
27 method accept(v: Visitor) is
28 v.visitRectangle(this
this)
29
30 class CompoundShape implements Shape is
31 // ...
32 method accept(v: Visitor) is
33 v.visitCompoundShape(this
this)
34
35
36 // La interfaz Visitor declara un grupo de métodos de visita que
37 // se corresponden con clases de elemento. La firma de un método
38 // de visita permite al visitante identificar la clase exacta
39 // del elemento con el que trata.
40 interface Visitor is
41 method visitDot(d: Dot)
42 method visitCircle(c: Circle)
43 method visitRectangle(r: Rectangle)
[email protected] (#160493)
431 Patrones de comportamiento / Visitor #160493
[email protected] (#160493)
432 Patrones de comportamiento / Visitor #160493
Aplicabilidad
Utiliza el patrón Visitor cuando necesites realizar una opera-
ción sobre todos los elementos de una compleja estructura de
objetos (por ejemplo, un árbol de objetos).
[email protected] (#160493)
433 Patrones de comportamiento / Visitor #160493
Cómo implementarlo
1. Declara la interfaz visitante con un grupo de métodos “visita-
ntes”, uno por cada clase de elemento concreto existente en el
programa.
[email protected] (#160493)
434 Patrones de comportamiento / Visitor #160493
Pros y contras
Principio de abierto/cerrado. Puedes introducir un nuevo com-
portamiento que puede funcionar con objetos de clases dife-
rentes sin cambiar esas clases.
Principio de responsabilidad única. Puedes tomar varias versio-
nes del mismo comportamiento y ponerlas en la misma clase.
Un objeto visitante puede acumular cierta información útil
mientras trabaja con varios objetos. Esto puede resultar útil
[email protected] (#160493)
435 Patrones de comportamiento / Visitor #160493
Debes actualizar todos los visitantes cada vez que una clase se
añada o elimine de la jerarquía de elementos.
Los visitantes pueden carecer del acceso necesario a los cam-
pos y métodos privados de los elementos con los que se supo-
ne que deben trabajar.
• Puedes utilizar Visitor junto con Iterator para recorrer una es-
tructura de datos compleja y ejecutar alguna operación sobre
sus elementos, incluso aunque todos tengan clases distintas.
[email protected] (#160493)
#160493
Conclusión
¡Felicidades! ¡Has llegado al final del libro!
Sin embargo, hay muchos otros patrones en el mundo. Espe-
ro que el libro se convierta en tu punto de partida para apre-
nder patrones y desarrollar superpoderes para el diseño de
programas.
[email protected] (#160493)