Design Patterns Es
Design Patterns Es
Design Patterns Es
Sumérggete en lo
loss
PATR
TRONE
ONESS
DE
DI
DISEÑO
SEÑO
v2022-1.17
Í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
salguerojonatan@gmail.com (#92924)
5 Índice de contenido #92924
salguerojonatan@gmail.com (#92924)
6 Cómo leer este libro #92924
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.
salguerojonatan@gmail.com (#92924)
#92924
FUNDAMENTOS
DE LA POO
salguerojonatan@gmail.com (#92924)
8 Fundamentos de la POO / Conceptos básicos de POO #92924
Objetos, clases
¿Te gustan los gatos? Espero que sí, porque voy a intentar
explicar los conceptos de POO utilizando varios ejemplos
con gatos.
salguerojonatan@gmail.com (#92924)
9 Fundamentos de la POO / Conceptos básicos de POO #92924
salguerojonatan@gmail.com (#92924)
10 Fundamentos de la POO / Conceptos básicos de POO #92924
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.
salguerojonatan@gmail.com (#92924)
11 Fundamentos de la POO / Conceptos básicos de POO #92924
salguerojonatan@gmail.com (#92924)
12 Fundamentos de la POO / Conceptos básicos de POO #92924
salguerojonatan@gmail.com (#92924)
13 Fundamentos de la POO / Los pilares de la POO #92924
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.
salguerojonatan@gmail.com (#92924)
14 Fundamentos de la POO / Los pilares de la POO #92924
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-
salguerojonatan@gmail.com (#92924)
15 Fundamentos de la POO / Los pilares de la POO #92924
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.
salguerojonatan@gmail.com (#92924)
16 Fundamentos de la POO / Los pilares de la POO #92924
salguerojonatan@gmail.com (#92924)
17 Fundamentos de la POO / Los pilares de la POO #92924
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.
salguerojonatan@gmail.com (#92924)
18 Fundamentos de la POO / Los pilares de la POO #92924
Polimorfismo
Veamos algunos ejemplos con animales. La mayoría de los
Animal puede emitir sonidos. Podemos anticipar que todas
salguerojonatan@gmail.com (#92924)
19 Fundamentos de la POO / Los pilares de la POO #92924
salguerojonatan@gmail.com (#92924)
20 Fundamentos de la POO / Los pilares de la POO #92924
1 bag = [new
new Cat(), new Dog()];
2
3 foreach (Animal a : bag)
4 a.makeSound()
5
6 // ¡Miau!
7 // ¡Guau!
salguerojonatan@gmail.com (#92924)
21 Fundamentos de la POO / Relaciones entre objetos #92924
Dependencia
salguerojonatan@gmail.com (#92924)
22 Fundamentos de la POO / Relaciones entre objetos #92924
Asociación
salguerojonatan@gmail.com (#92924)
23 Fundamentos de la POO / Relaciones entre objetos #92924
1 class Professor is
2 field Student student
3 // ...
4 method teach(Course c) is
5 // ...
6 this
this.student.remember(c.getKnowledge())
salguerojonatan@gmail.com (#92924)
24 Fundamentos de la POO / Relaciones entre objetos #92924
Agregación
salguerojonatan@gmail.com (#92924)
25 Fundamentos de la POO / Relaciones entre objetos #92924
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?”.
salguerojonatan@gmail.com (#92924)
26 Fundamentos de la POO / Relaciones entre objetos #92924
salguerojonatan@gmail.com (#92924)
#92924
INTRODUCCIÓN
A LOS PATRONES
salguerojonatan@gmail.com (#92924)
28 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #92924
salguerojonatan@gmail.com (#92924)
29 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #92924
salguerojonatan@gmail.com (#92924)
30 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #92924
Los patrones más universales y de más alto nivel son los pat-
rones 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.
salguerojonatan@gmail.com (#92924)
31 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #92924
salguerojonatan@gmail.com (#92924)
32 Introducción a los patrones de diseño / ¿Qué es un patrón de diseño? #92924
salguerojonatan@gmail.com (#92924)
33 #92924
Introducción a los patrones de diseño / ¿Por qué debería aprender sobre patrones?
salguerojonatan@gmail.com (#92924)
#92924
PRINCIPIOS
DE DISEÑO
DE SOFTWARE
salguerojonatan@gmail.com (#92924)
35 Principios de diseño de software / Características del buen diseño #92924
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 desar-
rollo significa que habrá más dinero disponible para marketing
y un alcance más amplio a clientes potenciales.
salguerojonatan@gmail.com (#92924)
36 Principios de diseño de software / Reutilización de código #92924
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:
salguerojonatan@gmail.com (#92924)
37 Principios de diseño de software / Extensibilidad #92924
„
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.
salguerojonatan@gmail.com (#92924)
38 Principios de diseño de software / Extensibilidad #92924
salguerojonatan@gmail.com (#92924)
39 Principios del diseño #92924
salguerojonatan@gmail.com (#92924)
40 Principios del diseño / Encapsula lo que varía #92924
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.
salguerojonatan@gmail.com (#92924)
41 Principios del diseño / Encapsula lo que varía #92924
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.
salguerojonatan@gmail.com (#92924)
42 Principios del diseño / Encapsula lo que varía #92924
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
salguerojonatan@gmail.com (#92924)
43 Principios del diseño / Encapsula lo que varía #92924
salguerojonatan@gmail.com (#92924)
44 Principios del diseño / Encapsula lo que varía #92924
salguerojonatan@gmail.com (#92924)
45 Principios del diseño / Programa a una interfaz, no a una implementación #92924
salguerojonatan@gmail.com (#92924)
46 Principios del diseño / Programa a una interfaz, no a una implementación #92924
salguerojonatan@gmail.com (#92924)
47 Principios del diseño / Programa a una interfaz, no a una implementación #92924
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.
salguerojonatan@gmail.com (#92924)
48 Principios del diseño / Programa a una interfaz, no a una implementación #92924
salguerojonatan@gmail.com (#92924)
49 Principios del diseño / Programa a una interfaz, no a una implementación #92924
salguerojonatan@gmail.com (#92924)
50 Principios del diseño / Favorece la composición sobre la herencia #92924
salguerojonatan@gmail.com (#92924)
51 Principios del diseño / Favorece la composición sobre la herencia #92924
salguerojonatan@gmail.com (#92924)
52 Principios del diseño / Favorece la composición sobre la herencia #92924
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.
salguerojonatan@gmail.com (#92924)
53 Principios del diseño / Favorece la composición sobre la herencia #92924
salguerojonatan@gmail.com (#92924)
54 Principios SOLID #92924
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 .
salguerojonatan@gmail.com (#92924)
55 Principios SOLID / S: Principio de responsabilidad única #92924
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.
salguerojonatan@gmail.com (#92924)
56 Principios SOLID / S: Principio de responsabilidad única #92924
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.
salguerojonatan@gmail.com (#92924)
57 Principios SOLID / O: Principio de abierto/cerrado #92924
O pen/Closed Principle
Principio de abierto/cerrado
salguerojonatan@gmail.com (#92924)
58 Principios SOLID / O: Principio de abierto/cerrado #92924
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
salguerojonatan@gmail.com (#92924)
59 Principios SOLID / O: Principio de abierto/cerrado #92924
salguerojonatan@gmail.com (#92924)
60 Principios SOLID / O: Principio de abierto/cerrado #92924
salguerojonatan@gmail.com (#92924)
61 Principios SOLID / L: Principio de sustitución de Liskov #92924
salguerojonatan@gmail.com (#92924)
62 Principios SOLID / L: Principio de sustitución de Liskov #92924
◦ 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.
salguerojonatan@gmail.com (#92924)
63 Principios SOLID / L: Principio de sustitución de Liskov #92924
◦ Digamos que
tienes una clase con el método
comprarGato(): Gato . El código cliente espera recibir cual-
salguerojonatan@gmail.com (#92924)
64 Principios SOLID / L: Principio de sustitución de Liskov #92924
salguerojonatan@gmail.com (#92924)
65 Principios SOLID / L: Principio de sustitución de Liskov #92924
salguerojonatan@gmail.com (#92924)
66 Principios SOLID / L: Principio de sustitución de Liskov #92924
Ejemplo
Veamos un ejemplo de una jerarquía de clases de documento
que violan el principio de sustitución.
salguerojonatan@gmail.com (#92924)
67 Principios SOLID / L: Principio de sustitución de Liskov #92924
salguerojonatan@gmail.com (#92924)
68 Principios SOLID / I: Principio de segregación de la interfaz #92924
salguerojonatan@gmail.com (#92924)
69 Principios SOLID / I: Principio de segregación de la interfaz #92924
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.
salguerojonatan@gmail.com (#92924)
70 Principios SOLID / I: Principio de segregación de la interfaz #92924
salguerojonatan@gmail.com (#92924)
71 Principios SOLID / D: Principio de inversión de la dependencia #92924
salguerojonatan@gmail.com (#92924)
72 Principios SOLID / D: Principio de inversión de la dependencia #92924
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-
salguerojonatan@gmail.com (#92924)
73 Principios SOLID / D: Principio de inversión de la dependencia #92924
ANTES: una clase de alto nivel depende de una clase de bajo nivel.
salguerojonatan@gmail.com (#92924)
74 Principios SOLID / D: Principio de inversión de la dependencia #92924
salguerojonatan@gmail.com (#92924)
#92924
EL CATÁLOGO
DE PATRONES
DE DISEÑO
salguerojonatan@gmail.com (#92924)
76 Patrones creacionales #92924
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.
salguerojonatan@gmail.com (#92924)
77 Patrones creacionales #92924
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.
salguerojonatan@gmail.com (#92924)
78 Patrones creacionales / Factory Method #92924
FACTORY METHOD
También llamado: Método fábrica, Constructor virtual
salguerojonatan@gmail.com (#92924)
79 Patrones creacionales / Factory Method #92924
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 .
salguerojonatan@gmail.com (#92924)
80 Patrones creacionales / Factory Method #92924
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.
salguerojonatan@gmail.com (#92924)
81 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
82 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
83 Patrones creacionales / Factory Method #92924
Estructura
salguerojonatan@gmail.com (#92924)
84 Patrones creacionales / Factory Method #92924
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.
salguerojonatan@gmail.com (#92924)
85 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
86 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
87 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
88 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
89 Patrones creacionales / Factory Method #92924
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.
salguerojonatan@gmail.com (#92924)
90 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
91 Patrones creacionales / Factory Method #92924
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.
salguerojonatan@gmail.com (#92924)
92 Patrones creacionales / Factory Method #92924
como con objetos Tren . Puedes crear una nueva subclase (di-
salguerojonatan@gmail.com (#92924)
93 Patrones creacionales / Factory Method #92924
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.
salguerojonatan@gmail.com (#92924)
94 Patrones creacionales / Factory Method #92924
salguerojonatan@gmail.com (#92924)
95 Patrones creacionales / Abstract Factory #92924
ABSTRACT FACTORY
También llamado: Fábrica abstracta
salguerojonatan@gmail.com (#92924)
96 Patrones creacionales / Abstract Factory #92924
Problema
Imagina que estás creando un simulador de tienda de mueb-
les. Tu código está compuesto por clases que representan lo
siguiente:
salguerojonatan@gmail.com (#92924)
97 Patrones creacionales / Abstract Factory #92924
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í
salguerojonatan@gmail.com (#92924)
98 Patrones creacionales / Abstract Factory #92924
Todas las variantes del mismo objeto deben moverse a una única jerarquía
de clase.
salguerojonatan@gmail.com (#92924)
99 Patrones creacionales / Abstract Factory #92924
salguerojonatan@gmail.com (#92924)
100 Patrones creacionales / Abstract Factory #92924
salguerojonatan@gmail.com (#92924)
101 Patrones creacionales / Abstract Factory #92924
Estructura
salguerojonatan@gmail.com (#92924)
102 Patrones creacionales / Abstract Factory #92924
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.
salguerojonatan@gmail.com (#92924)
103 Patrones creacionales / Abstract Factory #92924
salguerojonatan@gmail.com (#92924)
104 Patrones creacionales / Abstract Factory #92924
salguerojonatan@gmail.com (#92924)
105 Patrones creacionales / Abstract Factory #92924
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.
salguerojonatan@gmail.com (#92924)
106 Patrones creacionales / Abstract Factory #92924
salguerojonatan@gmail.com (#92924)
107 Patrones creacionales / Abstract Factory #92924
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.
salguerojonatan@gmail.com (#92924)
108 Patrones creacionales / Abstract Factory #92924
Cómo implementarlo
1. Mapea una matriz de distintos tipos de productos frente a va-
riantes de dichos productos.
salguerojonatan@gmail.com (#92924)
109 Patrones creacionales / Abstract Factory #92924
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.
salguerojonatan@gmail.com (#92924)
110 Patrones creacionales / Abstract Factory #92924
salguerojonatan@gmail.com (#92924)
111 Patrones creacionales / Builder #92924
BUILDER
También llamado: Constructor
salguerojonatan@gmail.com (#92924)
112 Patrones creacionales / Builder #92924
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.
salguerojonatan@gmail.com (#92924)
113 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
114 Patrones creacionales / Builder #92924
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.
salguerojonatan@gmail.com (#92924)
115 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
116 Patrones creacionales / Builder #92924
Clase directora
salguerojonatan@gmail.com (#92924)
117 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
118 Patrones creacionales / Builder #92924
Estructura
salguerojonatan@gmail.com (#92924)
119 Patrones creacionales / Builder #92924
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.
salguerojonatan@gmail.com (#92924)
120 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
121 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
122 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
123 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
124 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
125 Patrones creacionales / Builder #92924
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)
salguerojonatan@gmail.com (#92924)
126 Patrones creacionales / Builder #92924
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”.
salguerojonatan@gmail.com (#92924)
127 Patrones creacionales / Builder #92924
1 class Pizza {
2 Pizza(int size) { ... }
3 Pizza(int size, boolean cheese) { ... }
4 Pizza(int size, boolean cheese, boolean pepperoni) { ... }
5 // ...
salguerojonatan@gmail.com (#92924)
128 Patrones creacionales / Builder #92924
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.
salguerojonatan@gmail.com (#92924)
129 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
130 Patrones creacionales / Builder #92924
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.
salguerojonatan@gmail.com (#92924)
131 Patrones creacionales / Builder #92924
salguerojonatan@gmail.com (#92924)
132 Patrones creacionales / Prototype #92924
PROTOTYPE
También llamado: Prototipo, Clon, Clone
salguerojonatan@gmail.com (#92924)
133 Patrones creacionales / Prototype #92924
Problema
Digamos que tienes un objeto y quieres crear una copia exa-
cta 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
salguerojonatan@gmail.com (#92924)
134 Patrones creacionales / Prototype #92924
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 .
salguerojonatan@gmail.com (#92924)
135 Patrones creacionales / Prototype #92924
salguerojonatan@gmail.com (#92924)
136 Patrones creacionales / Prototype #92924
salguerojonatan@gmail.com (#92924)
137 Patrones creacionales / Prototype #92924
Estructura
Implementación básica
salguerojonatan@gmail.com (#92924)
138 Patrones creacionales / Prototype #92924
salguerojonatan@gmail.com (#92924)
139 Patrones creacionales / Prototype #92924
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
salguerojonatan@gmail.com (#92924)
140 Patrones creacionales / Prototype #92924
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
salguerojonatan@gmail.com (#92924)
141 Patrones creacionales / Prototype #92924
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()
salguerojonatan@gmail.com (#92924)
142 Patrones creacionales / Prototype #92924
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`.
salguerojonatan@gmail.com (#92924)
143 Patrones creacionales / Prototype #92924
Aplicabilidad
Utiliza el patrón Prototype cuando tu código no deba depender
de las clases concretas de objetos que necesites copiar.
salguerojonatan@gmail.com (#92924)
144 Patrones creacionales / Prototype #92924
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.
salguerojonatan@gmail.com (#92924)
145 Patrones creacionales / Prototype #92924
Pros y contras
Puedes clonar objetos sin acoplarlos a sus clases concretas.
salguerojonatan@gmail.com (#92924)
146 Patrones creacionales / Prototype #92924
salguerojonatan@gmail.com (#92924)
147 Patrones creacionales / Prototype #92924
salguerojonatan@gmail.com (#92924)
148 Patrones creacionales / Singleton #92924
SINGLETON
También llamado: Instancia única
salguerojonatan@gmail.com (#92924)
149 Patrones creacionales / Singleton #92924
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.
salguerojonatan@gmail.com (#92924)
150 Patrones creacionales / Singleton #92924
Solución
Todas las implementaciones del patrón Singleton tienen estos
dos pasos en común:
salguerojonatan@gmail.com (#92924)
151 Patrones creacionales / Singleton #92924
salguerojonatan@gmail.com (#92924)
152 Patrones creacionales / Singleton #92924
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é
salguerojonatan@gmail.com (#92924)
153 Patrones creacionales / Singleton #92924
salguerojonatan@gmail.com (#92924)
154 Patrones creacionales / Singleton #92924
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.
salguerojonatan@gmail.com (#92924)
155 Patrones creacionales / Singleton #92924
Cómo implementarlo
1. Añade un campo estático privado a la clase para almacenar la
instancia Singleton.
salguerojonatan@gmail.com (#92924)
156 Patrones creacionales / Singleton #92924
Pros y contras
Puedes tener la certeza de que una clase tiene una única
instancia.
Obtienes un punto de acceso global a dicha instancia.
salguerojonatan@gmail.com (#92924)
157 Patrones creacionales / Singleton #92924
salguerojonatan@gmail.com (#92924)
158 Patrones estructurales #92924
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 incompatib-
les.
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.
salguerojonatan@gmail.com (#92924)
159 Patrones estructurales #92924
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.
salguerojonatan@gmail.com (#92924)
160 Patrones estructurales #92924
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.
salguerojonatan@gmail.com (#92924)
161 Patrones estructurales / Adapter #92924
ADAPTER
También llamado: Adaptador, Envoltorio, Wrapper
salguerojonatan@gmail.com (#92924)
162 Patrones estructurales / Adapter #92924
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.
salguerojonatan@gmail.com (#92924)
163 Patrones estructurales / Adapter #92924
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.
salguerojonatan@gmail.com (#92924)
164 Patrones estructurales / Adapter #92924
salguerojonatan@gmail.com (#92924)
165 Patrones estructurales / Adapter #92924
Estructura
Adaptador de objetos
salguerojonatan@gmail.com (#92924)
166 Patrones estructurales / Adapter #92924
salguerojonatan@gmail.com (#92924)
167 Patrones estructurales / Adapter #92924
Clase adaptadora
salguerojonatan@gmail.com (#92924)
168 Patrones estructurales / Adapter #92924
Pseudocódigo
Este ejemplo del patrón Adapter se basa en el clásico conflicto
entre piezas cuadradas y agujeros redondos.
salguerojonatan@gmail.com (#92924)
169 Patrones estructurales / Adapter #92924
salguerojonatan@gmail.com (#92924)
170 Patrones estructurales / Adapter #92924
Aplicabilidad
Utiliza la clase adaptadora cuando quieras usar una clase exi-
stente, pero cuya interfaz no sea compatible con el resto del
código.
salguerojonatan@gmail.com (#92924)
171 Patrones estructurales / Adapter #92924
Cómo implementarlo
1. Asegúrate de que tienes al menos dos clases con interfaces in-
compatibles:
salguerojonatan@gmail.com (#92924)
172 Patrones estructurales / Adapter #92924
salguerojonatan@gmail.com (#92924)
173 Patrones estructurales / Adapter #92924
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.
salguerojonatan@gmail.com (#92924)
174 Patrones estructurales / Adapter #92924
salguerojonatan@gmail.com (#92924)
175 Patrones estructurales / Bridge #92924
BRIDGE
También llamado: Puente
salguerojonatan@gmail.com (#92924)
176 Patrones estructurales / Bridge #92924
Problema
¿Abstracción? ¿Implementación? ¿Asusta? Mantengamos la
calma y veamos un ejemplo sencillo.
salguerojonatan@gmail.com (#92924)
177 Patrones estructurales / Bridge #92924
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.
salguerojonatan@gmail.com (#92924)
178 Patrones estructurales / Bridge #92924
Abstracción e implementación
1
El libro de la GoF introduce los términos Abstracción e Imp-
lementació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.
salguerojonatan@gmail.com (#92924)
179 Patrones estructurales / Bridge #92924
salguerojonatan@gmail.com (#92924)
180 Patrones estructurales / Bridge #92924
salguerojonatan@gmail.com (#92924)
181 Patrones estructurales / Bridge #92924
salguerojonatan@gmail.com (#92924)
182 Patrones estructurales / Bridge #92924
Estructura
salguerojonatan@gmail.com (#92924)
183 Patrones estructurales / Bridge #92924
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.
salguerojonatan@gmail.com (#92924)
184 Patrones estructurales / Bridge #92924
salguerojonatan@gmail.com (#92924)
185 Patrones estructurales / Bridge #92924
salguerojonatan@gmail.com (#92924)
186 Patrones estructurales / Bridge #92924
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)
salguerojonatan@gmail.com (#92924)
187 Patrones estructurales / Bridge #92924
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).
salguerojonatan@gmail.com (#92924)
188 Patrones estructurales / Bridge #92924
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.
salguerojonatan@gmail.com (#92924)
189 Patrones estructurales / Bridge #92924
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.
salguerojonatan@gmail.com (#92924)
190 Patrones estructurales / Bridge #92924
salguerojonatan@gmail.com (#92924)
191 Patrones estructurales / Bridge #92924
salguerojonatan@gmail.com (#92924)
192 Patrones estructurales / Composite #92924
COMPOSITE
También llamado: Objeto compuesto, Object Tree
salguerojonatan@gmail.com (#92924)
193 Patrones estructurales / Composite #92924
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.
salguerojonatan@gmail.com (#92924)
194 Patrones estructurales / Composite #92924
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
salguerojonatan@gmail.com (#92924)
195 Patrones estructurales / Composite #92924
salguerojonatan@gmail.com (#92924)
196 Patrones estructurales / Composite #92924
Estructura
salguerojonatan@gmail.com (#92924)
197 Patrones estructurales / Composite #92924
salguerojonatan@gmail.com (#92924)
198 Patrones estructurales / Composite #92924
Pseudocódigo
En este ejemplo, el patrón Composite te permite implementar
el apilamiento (stacking) de formas geométricas en un editor
gráfico.
salguerojonatan@gmail.com (#92924)
199 Patrones estructurales / Composite #92924
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.
salguerojonatan@gmail.com (#92924)
200 Patrones estructurales / Composite #92924
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)
salguerojonatan@gmail.com (#92924)
201 Patrones estructurales / Composite #92924
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()
salguerojonatan@gmail.com (#92924)
202 Patrones estructurales / Composite #92924
Aplicabilidad
Utiliza el patrón Composite cuando tengas que implementar
una estructura de objetos con forma de árbol.
salguerojonatan@gmail.com (#92924)
203 Patrones estructurales / Composite #92924
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.
salguerojonatan@gmail.com (#92924)
204 Patrones estructurales / Composite #92924
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.
salguerojonatan@gmail.com (#92924)
205 Patrones estructurales / Composite #92924
salguerojonatan@gmail.com (#92924)
206 Patrones estructurales / Decorator #92924
DECORATOR
También llamado: Decorador, Envoltorio, Wrapper
salguerojonatan@gmail.com (#92924)
207 Patrones estructurales / Decorator #92924
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.
salguerojonatan@gmail.com (#92924)
208 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
209 Patrones estructurales / Decorator #92924
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.
salguerojonatan@gmail.com (#92924)
210 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
211 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
212 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
213 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
214 Patrones estructurales / Decorator #92924
Estructura
salguerojonatan@gmail.com (#92924)
215 Patrones estructurales / Decorator #92924
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.
salguerojonatan@gmail.com (#92924)
216 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
217 Patrones estructurales / Decorator #92924
• Después de que los datos son leídos del disco, pasan por los
mismos decoradores, que los descomprimen y decodifican.
salguerojonatan@gmail.com (#92924)
218 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
219 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
220 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
221 Patrones estructurales / Decorator #92924
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.
salguerojonatan@gmail.com (#92924)
222 Patrones estructurales / Decorator #92924
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.
salguerojonatan@gmail.com (#92924)
223 Patrones estructurales / Decorator #92924
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.
salguerojonatan@gmail.com (#92924)
224 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
225 Patrones estructurales / Decorator #92924
salguerojonatan@gmail.com (#92924)
226 Patrones estructurales / Facade #92924
FACADE
También llamado: Fachada
salguerojonatan@gmail.com (#92924)
227 Patrones estructurales / Facade #92924
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.
salguerojonatan@gmail.com (#92924)
228 Patrones estructurales / Facade #92924
salguerojonatan@gmail.com (#92924)
229 Patrones estructurales / Facade #92924
Estructura
salguerojonatan@gmail.com (#92924)
230 Patrones estructurales / Facade #92924
Pseudocódigo
En este ejemplo, el patrón Facade simplifica la interacción con
un framework complejo de conversión de vídeo.
salguerojonatan@gmail.com (#92924)
231 Patrones estructurales / Facade #92924
salguerojonatan@gmail.com (#92924)
232 Patrones estructurales / Facade #92924
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.
salguerojonatan@gmail.com (#92924)
233 Patrones estructurales / Facade #92924
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.
salguerojonatan@gmail.com (#92924)
234 Patrones estructurales / Facade #92924
Pros y contras
Puedes aislar tu código de la complejidad de un subsistema.
salguerojonatan@gmail.com (#92924)
235 Patrones estructurales / Facade #92924
salguerojonatan@gmail.com (#92924)
236 Patrones estructurales / Facade #92924
salguerojonatan@gmail.com (#92924)
237 Patrones estructurales / Flyweight #92924
FLYWEIGHT
También llamado: Peso mosca, Peso ligero, Cache
salguerojonatan@gmail.com (#92924)
238 Patrones estructurales / Flyweight #92924
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 distinga
de otros juegos. Grandes cantidades de balas, misiles y metral-
la de las explosiones volarán por todo el mapa, ofreciendo una
apasionante experiencia al jugador.
salguerojonatan@gmail.com (#92924)
239 Patrones estructurales / Flyweight #92924
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.
salguerojonatan@gmail.com (#92924)
240 Patrones estructurales / Flyweight #92924
salguerojonatan@gmail.com (#92924)
241 Patrones estructurales / Flyweight #92924
salguerojonatan@gmail.com (#92924)
242 Patrones estructurales / Flyweight #92924
salguerojonatan@gmail.com (#92924)
243 Patrones estructurales / Flyweight #92924
Flyweight y la inmutabilidad
Fábrica flyweight
salguerojonatan@gmail.com (#92924)
244 Patrones estructurales / Flyweight #92924
Estructura
salguerojonatan@gmail.com (#92924)
245 Patrones estructurales / Flyweight #92924
salguerojonatan@gmail.com (#92924)
246 Patrones estructurales / Flyweight #92924
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.
salguerojonatan@gmail.com (#92924)
247 Patrones estructurales / Flyweight #92924
salguerojonatan@gmail.com (#92924)
248 Patrones estructurales / Flyweight #92924
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)
salguerojonatan@gmail.com (#92924)
249 Patrones estructurales / Flyweight #92924
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:
salguerojonatan@gmail.com (#92924)
250 Patrones estructurales / Flyweight #92924
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.
salguerojonatan@gmail.com (#92924)
251 Patrones estructurales / Flyweight #92924
salguerojonatan@gmail.com (#92924)
252 Patrones estructurales / Proxy #92924
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.
salguerojonatan@gmail.com (#92924)
253 Patrones estructurales / Proxy #92924
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.
salguerojonatan@gmail.com (#92924)
254 Patrones estructurales / Proxy #92924
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.
salguerojonatan@gmail.com (#92924)
255 Patrones estructurales / Proxy #92924
Las tarjetas de crédito pueden utilizarse para realizar pagos tanto como
el efectivo.
salguerojonatan@gmail.com (#92924)
256 Patrones estructurales / Proxy #92924
Estructura
salguerojonatan@gmail.com (#92924)
257 Patrones estructurales / Proxy #92924
Pseudocódigo
Este ejemplo ilustra cómo el patrón Proxy puede ayudar a int-
roducir la inicialización diferida y el almacenamiento en caché
a una biblioteca de integración de YouTube de un tercero.
salguerojonatan@gmail.com (#92924)
258 Patrones estructurales / Proxy #92924
salguerojonatan@gmail.com (#92924)
259 Patrones estructurales / Proxy #92924
salguerojonatan@gmail.com (#92924)
260 Patrones estructurales / Proxy #92924
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)
83 manager.reactOnUserInput()
salguerojonatan@gmail.com (#92924)
261 Patrones estructurales / Proxy #92924
Aplicabilidad
Hay decenas de formas de utilizar el patrón Proxy. Repasemos
los usos más populares.
salguerojonatan@gmail.com (#92924)
262 Patrones estructurales / Proxy #92924
salguerojonatan@gmail.com (#92924)
263 Patrones estructurales / Proxy #92924
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.
salguerojonatan@gmail.com (#92924)
264 Patrones estructurales / Proxy #92924
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.
salguerojonatan@gmail.com (#92924)
265 Patrones estructurales / Proxy #92924
salguerojonatan@gmail.com (#92924)
266 Patrones de comportamiento #92924
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.
salguerojonatan@gmail.com (#92924)
267 Patrones de comportamiento #92924
Iterator
Permite recorrer elementos de una colección sin exponer su rep-
resentación subyacente (lista, pila, árbol, etc.).
Mediator
Permite reducir las dependencias caóticas entre objetos. El pat-
ró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.
salguerojonatan@gmail.com (#92924)
268 Patrones de comportamiento #92924
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.
salguerojonatan@gmail.com (#92924)
269 Patrones de comportamiento #92924
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.
salguerojonatan@gmail.com (#92924)
270 Patrones de comportamiento / Chain of Responsibility #92924
CHAIN OF
RESPONSIBILITY
También llamado: Cadena de responsabilidad, CoR,
Chain of Command
salguerojonatan@gmail.com (#92924)
271 Patrones de comportamiento / Chain of Responsibility #92924
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.
salguerojonatan@gmail.com (#92924)
272 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
273 Patrones de comportamiento / Chain of Responsibility #92924
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.
salguerojonatan@gmail.com (#92924)
274 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
275 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
276 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
277 Patrones de comportamiento / Chain of Responsibility #92924
Estructura
salguerojonatan@gmail.com (#92924)
278 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
279 Patrones de comportamiento / Chain of Responsibility #92924
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.
salguerojonatan@gmail.com (#92924)
280 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
281 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
282 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
283 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
284 Patrones de comportamiento / Chain of Responsibility #92924
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.
salguerojonatan@gmail.com (#92924)
285 Patrones de comportamiento / Chain of Responsibility #92924
Cómo implementarlo
1. Declara la interfaz manejadora y describe la firma de un méto-
do para manejar solicitudes.
salguerojonatan@gmail.com (#92924)
286 Patrones de comportamiento / Chain of Responsibility #92924
◦ Si procesa la solicitud.
Pros y contras
Puedes controlar el orden de control de solicitudes.
salguerojonatan@gmail.com (#92924)
287 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
288 Patrones de comportamiento / Chain of Responsibility #92924
salguerojonatan@gmail.com (#92924)
289 Patrones de comportamiento / Command #92924
COMMAND
También llamado: Comando, Orden, Action, Transaction
salguerojonatan@gmail.com (#92924)
290 Patrones de comportamiento / Command #92924
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.
salguerojonatan@gmail.com (#92924)
291 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
292 Patrones de comportamiento / Command #92924
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.
salguerojonatan@gmail.com (#92924)
293 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
294 Patrones de comportamiento / Command #92924
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.
salguerojonatan@gmail.com (#92924)
295 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
296 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
297 Patrones de comportamiento / Command #92924
Estructura
salguerojonatan@gmail.com (#92924)
298 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
299 Patrones de comportamiento / Command #92924
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.
salguerojonatan@gmail.com (#92924)
300 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
301 Patrones de comportamiento / Command #92924
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)
salguerojonatan@gmail.com (#92924)
302 Patrones de comportamiento / Command #92924
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
salguerojonatan@gmail.com (#92924)
303 Patrones de comportamiento / Command #92924
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(
salguerojonatan@gmail.com (#92924)
304 Patrones de comportamiento / Command #92924
Aplicabilidad
Utiliza el patrón Command cuando quieras parametrizar obje-
tos con operaciones.
salguerojonatan@gmail.com (#92924)
305 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
306 Patrones de comportamiento / Command #92924
Cómo implementarlo
1. Declara la interfaz de comando con un único método de
ejecución.
salguerojonatan@gmail.com (#92924)
307 Patrones de comportamiento / Command #92924
◦ 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.
salguerojonatan@gmail.com (#92924)
308 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
309 Patrones de comportamiento / Command #92924
salguerojonatan@gmail.com (#92924)
310 Patrones de comportamiento / Iterator #92924
ITERATOR
También llamado: Iterador
salguerojonatan@gmail.com (#92924)
311 Patrones de comportamiento / Iterator #92924
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.
salguerojonatan@gmail.com (#92924)
312 Patrones de comportamiento / Iterator #92924
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.
salguerojonatan@gmail.com (#92924)
313 Patrones de comportamiento / Iterator #92924
salguerojonatan@gmail.com (#92924)
314 Patrones de comportamiento / Iterator #92924
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.
salguerojonatan@gmail.com (#92924)
315 Patrones de comportamiento / Iterator #92924
salguerojonatan@gmail.com (#92924)
316 Patrones de comportamiento / Iterator #92924
Estructura
salguerojonatan@gmail.com (#92924)
317 Patrones de comportamiento / Iterator #92924
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.
salguerojonatan@gmail.com (#92924)
318 Patrones de comportamiento / Iterator #92924
salguerojonatan@gmail.com (#92924)
319 Patrones de comportamiento / Iterator #92924
salguerojonatan@gmail.com (#92924)
320 Patrones de comportamiento / Iterator #92924
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 currentPosition++
55 return cache[currentPosition]
56
57 method hasMore() is
salguerojonatan@gmail.com (#92924)
321 Patrones de comportamiento / Iterator #92924
58 lazyInit()
59 return currentPosition < cache.length
60
61
62 // Aquí tienes otro truco útil: puedes pasar un iterador a una
63 // clase cliente en lugar de darle acceso a una colección
64 // completa. De esta forma, no expones la colección al cliente.
65 //
66 // Y hay otra ventaja: puedes cambiar la forma en la que el
67 // cliente trabaja con la colección durante el tiempo de
68 // ejecución pasándole un iterador diferente. Esto es posible
69 // porque el código cliente no está acoplado a clases iteradoras
70 // concretas.
71 class SocialSpammer is
72 method send(iterator: ProfileIterator, message: string) is
73 while (iterator.hasMore())
74 profile = iterator.getNext()
75 System.sendEmail(profile.getEmail(), message)
76
77
78 // La clase Aplicación configura colecciones e iteradores y
79 // después los pasa al código cliente.
80 class Application is
81 field network: SocialNetwork
82 field spammer: SocialSpammer
83
84 method config() is
85 if working with Facebook
86 this
this.network = new Facebook()
87 if working with LinkedIn
88 this
this.network = new LinkedIn()
89 this
this.spammer = new SocialSpammer()
salguerojonatan@gmail.com (#92924)
322 Patrones de comportamiento / Iterator #92924
90
91 method sendSpamToFriends(profile) is
92 iterator = network.createFriendsIterator(profile.getId())
93 spammer.send(iterator, "Very important message")
94
95 method sendSpamToCoworkers(profile) is
96 iterator = network.createCoworkersIterator(profile.getId())
97 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).
salguerojonatan@gmail.com (#92924)
323 Patrones de comportamiento / Iterator #92924
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.
salguerojonatan@gmail.com (#92924)
324 Patrones de comportamiento / Iterator #92924
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.
salguerojonatan@gmail.com (#92924)
325 Patrones de comportamiento / Iterator #92924
• 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.
salguerojonatan@gmail.com (#92924)
326 Patrones de comportamiento / Mediator #92924
MEDIATOR
También llamado: Mediador, Intermediary, Controller
salguerojonatan@gmail.com (#92924)
327 Patrones de comportamiento / Mediator #92924
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.
salguerojonatan@gmail.com (#92924)
328 Patrones de comportamiento / Mediator #92924
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.
salguerojonatan@gmail.com (#92924)
329 Patrones de comportamiento / Mediator #92924
salguerojonatan@gmail.com (#92924)
330 Patrones de comportamiento / Mediator #92924
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.
salguerojonatan@gmail.com (#92924)
331 Patrones de comportamiento / Mediator #92924
Estructura
salguerojonatan@gmail.com (#92924)
332 Patrones de comportamiento / Mediator #92924
salguerojonatan@gmail.com (#92924)
333 Patrones de comportamiento / Mediator #92924
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.
salguerojonatan@gmail.com (#92924)
334 Patrones de comportamiento / Mediator #92924
salguerojonatan@gmail.com (#92924)
335 Patrones de comportamiento / Mediator #92924
salguerojonatan@gmail.com (#92924)
336 Patrones de comportamiento / Mediator #92924
salguerojonatan@gmail.com (#92924)
337 Patrones de comportamiento / Mediator #92924
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.
salguerojonatan@gmail.com (#92924)
338 Patrones de comportamiento / Mediator #92924
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).
salguerojonatan@gmail.com (#92924)
339 Patrones de comportamiento / Mediator #92924
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.
salguerojonatan@gmail.com (#92924)
340 Patrones de comportamiento / Memento #92924
MEMENTO
También llamado: Recuerdo, Instantánea, Snapshot
salguerojonatan@gmail.com (#92924)
341 Patrones de comportamiento / Memento #92924
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.
salguerojonatan@gmail.com (#92924)
342 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
343 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
344 Patrones de comportamiento / Memento #92924
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.
salguerojonatan@gmail.com (#92924)
345 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
346 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
347 Patrones de comportamiento / Memento #92924
Estructura
Implementación basada en clases anidadas
salguerojonatan@gmail.com (#92924)
348 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
349 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
350 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
351 Patrones de comportamiento / Memento #92924
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.
salguerojonatan@gmail.com (#92924)
352 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
353 Patrones de comportamiento / Memento #92924
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)
salguerojonatan@gmail.com (#92924)
354 Patrones de comportamiento / Memento #92924
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.
salguerojonatan@gmail.com (#92924)
355 Patrones de comportamiento / Memento #92924
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-
salguerojonatan@gmail.com (#92924)
356 Patrones de comportamiento / Memento #92924
Pros y contras
Puedes producir instantáneas del estado del objeto sin violar
su encapsulación.
salguerojonatan@gmail.com (#92924)
357 Patrones de comportamiento / Memento #92924
salguerojonatan@gmail.com (#92924)
358 Patrones de comportamiento / Observer #92924
OBSERVER
También llamado: Observador, Publicación-Suscripción,
Modelo-patrón, Event-Subscriber, Listener
salguerojonatan@gmail.com (#92924)
359 Patrones de comportamiento / Observer #92924
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.
salguerojonatan@gmail.com (#92924)
360 Patrones de comportamiento / Observer #92924
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.
salguerojonatan@gmail.com (#92924)
361 Patrones de comportamiento / Observer #92924
salguerojonatan@gmail.com (#92924)
362 Patrones de comportamiento / Observer #92924
salguerojonatan@gmail.com (#92924)
363 Patrones de comportamiento / Observer #92924
Estructura
salguerojonatan@gmail.com (#92924)
364 Patrones de comportamiento / Observer #92924
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.
salguerojonatan@gmail.com (#92924)
365 Patrones de comportamiento / Observer #92924
salguerojonatan@gmail.com (#92924)
366 Patrones de comportamiento / Observer #92924
salguerojonatan@gmail.com (#92924)
367 Patrones de comportamiento / Observer #92924
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
salguerojonatan@gmail.com (#92924)
368 Patrones de comportamiento / Observer #92924
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 "admin@example.com",
88 "Someone has changed the file: %s")
89 editor.events.subscribe("save", emailAlerts)
salguerojonatan@gmail.com (#92924)
369 Patrones de comportamiento / Observer #92924
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.
salguerojonatan@gmail.com (#92924)
370 Patrones de comportamiento / Observer #92924
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.
salguerojonatan@gmail.com (#92924)
371 Patrones de comportamiento / Observer #92924
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.
salguerojonatan@gmail.com (#92924)
372 Patrones de comportamiento / Observer #92924
salguerojonatan@gmail.com (#92924)
373 Patrones de comportamiento / Observer #92924
salguerojonatan@gmail.com (#92924)
374 Patrones de comportamiento / State #92924
STATE
También llamado: Estado
salguerojonatan@gmail.com (#92924)
375 Patrones de comportamiento / State #92924
Problema
El patrón State está estrechamente relacionado con el conce-
1
pto de la Máquina de estados finitos .
salguerojonatan@gmail.com (#92924)
376 Patrones de comportamiento / State #92924
salguerojonatan@gmail.com (#92924)
377 Patrones de comportamiento / State #92924
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 // ...
salguerojonatan@gmail.com (#92924)
378 Patrones de comportamiento / State #92924
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.
salguerojonatan@gmail.com (#92924)
379 Patrones de comportamiento / State #92924
salguerojonatan@gmail.com (#92924)
380 Patrones de comportamiento / State #92924
Estructura
salguerojonatan@gmail.com (#92924)
381 Patrones de comportamiento / State #92924
salguerojonatan@gmail.com (#92924)
382 Patrones de comportamiento / State #92924
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.
salguerojonatan@gmail.com (#92924)
383 Patrones de comportamiento / State #92924
salguerojonatan@gmail.com (#92924)
384 Patrones de comportamiento / State #92924
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.
salguerojonatan@gmail.com (#92924)
385 Patrones de comportamiento / State #92924
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.
salguerojonatan@gmail.com (#92924)
386 Patrones de comportamiento / State #92924
salguerojonatan@gmail.com (#92924)
387 Patrones de comportamiento / State #92924
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.
salguerojonatan@gmail.com (#92924)
388 Patrones de comportamiento / State #92924
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.
salguerojonatan@gmail.com (#92924)
389 Patrones de comportamiento / State #92924
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.
salguerojonatan@gmail.com (#92924)
390 Patrones de comportamiento / State #92924
salguerojonatan@gmail.com (#92924)
391 Patrones de comportamiento / Strategy #92924
STRATEGY
También llamado: Estrategia
salguerojonatan@gmail.com (#92924)
392 Patrones de comportamiento / Strategy #92924
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.
salguerojonatan@gmail.com (#92924)
393 Patrones de comportamiento / Strategy #92924
salguerojonatan@gmail.com (#92924)
394 Patrones de comportamiento / Strategy #92924
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.
salguerojonatan@gmail.com (#92924)
395 Patrones de comportamiento / Strategy #92924
salguerojonatan@gmail.com (#92924)
396 Patrones de comportamiento / Strategy #92924
salguerojonatan@gmail.com (#92924)
397 Patrones de comportamiento / Strategy #92924
Estructura
salguerojonatan@gmail.com (#92924)
398 Patrones de comportamiento / Strategy #92924
Pseudocódigo
En este ejemplo, el contexto utiliza varias estrategias para eje-
cutar diversas operaciones aritméticas.
salguerojonatan@gmail.com (#92924)
399 Patrones de comportamiento / Strategy #92924
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.
salguerojonatan@gmail.com (#92924)
400 Patrones de comportamiento / Strategy #92924
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.
salguerojonatan@gmail.com (#92924)
401 Patrones de comportamiento / Strategy #92924
salguerojonatan@gmail.com (#92924)
402 Patrones de comportamiento / Strategy #92924
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.
salguerojonatan@gmail.com (#92924)
403 Patrones de comportamiento / Strategy #92924
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.
salguerojonatan@gmail.com (#92924)
404 Patrones de comportamiento / Strategy #92924
salguerojonatan@gmail.com (#92924)
405 Patrones de comportamiento / Strategy #92924
salguerojonatan@gmail.com (#92924)
406 Patrones de comportamiento / Template Method #92924
TEMPLATE METHOD
También llamado: Método plantilla
salguerojonatan@gmail.com (#92924)
407 Patrones de comportamiento / Template Method #92924
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.
salguerojonatan@gmail.com (#92924)
408 Patrones de comportamiento / Template Method #92924
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).
salguerojonatan@gmail.com (#92924)
409 Patrones de comportamiento / Template Method #92924
salguerojonatan@gmail.com (#92924)
410 Patrones de comportamiento / Template Method #92924
salguerojonatan@gmail.com (#92924)
411 Patrones de comportamiento / Template Method #92924
salguerojonatan@gmail.com (#92924)
412 Patrones de comportamiento / Template Method #92924
Estructura
salguerojonatan@gmail.com (#92924)
413 Patrones de comportamiento / Template Method #92924
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.
salguerojonatan@gmail.com (#92924)
414 Patrones de comportamiento / Template Method #92924
salguerojonatan@gmail.com (#92924)
415 Patrones de comportamiento / Template Method #92924
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
salguerojonatan@gmail.com (#92924)
416 Patrones de comportamiento / Template Method #92924
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.
salguerojonatan@gmail.com (#92924)
417 Patrones de comportamiento / Template Method #92924
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.
salguerojonatan@gmail.com (#92924)
418 Patrones de comportamiento / Template Method #92924
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.
salguerojonatan@gmail.com (#92924)
419 Patrones de comportamiento / Template Method #92924
salguerojonatan@gmail.com (#92924)
420 Patrones de comportamiento / Visitor #92924
VISITOR
También llamado: Visitante
salguerojonatan@gmail.com (#92924)
421 Patrones de comportamiento / Visitor #92924
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.
salguerojonatan@gmail.com (#92924)
422 Patrones de comportamiento / Visitor #92924
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.
salguerojonatan@gmail.com (#92924)
423 Patrones de comportamiento / Visitor #92924
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.
salguerojonatan@gmail.com (#92924)
424 Patrones de comportamiento / Visitor #92924
salguerojonatan@gmail.com (#92924)
425 Patrones de comportamiento / Visitor #92924
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 // ...
salguerojonatan@gmail.com (#92924)
426 Patrones de comportamiento / Visitor #92924
salguerojonatan@gmail.com (#92924)
427 Patrones de comportamiento / Visitor #92924
Estructura
salguerojonatan@gmail.com (#92924)
428 Patrones de comportamiento / Visitor #92924
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.
salguerojonatan@gmail.com (#92924)
429 Patrones de comportamiento / Visitor #92924
salguerojonatan@gmail.com (#92924)
430 Patrones de comportamiento / Visitor #92924
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)
salguerojonatan@gmail.com (#92924)
431 Patrones de comportamiento / Visitor #92924
salguerojonatan@gmail.com (#92924)
432 Patrones de comportamiento / Visitor #92924
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).
salguerojonatan@gmail.com (#92924)
433 Patrones de comportamiento / Visitor #92924
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.
salguerojonatan@gmail.com (#92924)
434 Patrones de comportamiento / Visitor #92924
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
salguerojonatan@gmail.com (#92924)
435 Patrones de comportamiento / Visitor #92924
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.
salguerojonatan@gmail.com (#92924)
#92924
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 ap-
render patrones y desarrollar superpoderes para el diseño de
programas.
salguerojonatan@gmail.com (#92924)