Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>Patrones</strong> <strong>de</strong> <strong>Diseño</strong><br />
Tema 7<br />
Grupo 46<br />
TACC II<br />
Curso 2008/09<br />
1
Indice<br />
� IIntroducción. t d ió<br />
� <strong>Patrones</strong>.<br />
� Descripción <strong>de</strong> los <strong>Patrones</strong>.<br />
� <strong>Ejemplo</strong>: <strong>Patrones</strong> en el MVC <strong>de</strong> Smalltalk.<br />
� El catálogo <strong>de</strong> patrones.<br />
� <strong>Patrones</strong> <strong>de</strong> Creación.<br />
� <strong>Patrones</strong> Estructurales.<br />
� <strong>Patrones</strong> <strong>de</strong> Comportamiento.<br />
�� CConclusiones. l i<br />
� Bibliografía.<br />
2
Introducción<br />
�� Di <strong>Diseño</strong> ñ específico ífi para el l problema, bl pero general l como<br />
para po<strong>de</strong>r a<strong>de</strong>cuarse a futuros requisitos y problemas.<br />
� Evitar el rediseño en la medida <strong>de</strong> lo posible.<br />
� Evitar resolver cada problema partiendo <strong>de</strong> cero.<br />
� Reutilizar soluciones que han sido útiles en el pasado.<br />
� <strong>Patrones</strong> recurrentes <strong>de</strong> clases y comunicación entre<br />
objetos en muchas soluciones <strong>de</strong> diseño.<br />
3
Patrón<br />
�� Un esquema que se usa para solucionar un problema problema.<br />
�� El esquema ha sido probado extensivamente, y ha<br />
funcionado. Se tiene experiencia sobre su uso.<br />
�� EExisten i t en muchos h ddominios: i i<br />
� Novelas y el cine: “héroe trágico”, “comedia romántica”, etc.<br />
� Arte.<br />
� Ingenierías.<br />
� Arquitectura.<br />
� Christopher p Alexan<strong>de</strong>r. “A Pattern Language: g g Towns, , Buildings, g ,<br />
Construction”. 1977.<br />
� http://www.patternlanguage.com<br />
4
<strong>Patrones</strong> <strong>de</strong> <strong>Diseño</strong><br />
�� RReutilizar tili di diseños ñ abstractos b t t que no iincluyan l d<strong>de</strong>talles t ll<br />
<strong>de</strong> la implementación.<br />
� Un patrón es una <strong>de</strong>scripción <strong>de</strong>l problema y la esencia<br />
<strong>de</strong> su solución, que q se ppue<strong>de</strong><br />
reutilizar en casos<br />
distintos.<br />
� EEs una solución l ió a<strong>de</strong>cuada d d a un problema bl común. ú<br />
�� AAsociado i d a orientación i t ió a objetos, bj t pero el l principio i i i<br />
general es aplicable a todos los enfoques <strong>de</strong> diseño<br />
software.<br />
5
<strong>Patrones</strong> <strong>de</strong> <strong>Diseño</strong><br />
�� DDocumentar t lla experiencia i i en el l di diseño, ñ en<br />
forma <strong>de</strong> un catálogo <strong>de</strong> patrones.<br />
� Categorías <strong>de</strong> patrones:<br />
� De creación: implica el proceso <strong>de</strong> instanciar objetos.<br />
� Estructurales: composición <strong>de</strong> objetos.<br />
�� De comportamiento comportamiento: cómo se com comunican nican los objetos objetos,<br />
cooperan y distribuyen las responsabilida<strong>de</strong>s para<br />
lograr sus objetivos.<br />
6
<strong>Patrones</strong> <strong>de</strong> <strong>Diseño</strong><br />
Estructura <strong>de</strong> un patrón<br />
�� NNombre b <strong>de</strong>l d l patrón. t ó<br />
� Describe el problema <strong>de</strong> diseño, junto con sus soluciones y<br />
consecuencias.<br />
�� VVocabulario b l i d<strong>de</strong> di diseño. ñ<br />
� Problema.<br />
� Describe cuándo aplicar el patrón.<br />
� Explica el problema y su contexto.<br />
� Solución.<br />
�� Elementos que forman el diseño, relaciones, responsabilida<strong>de</strong>s.<br />
� No un diseño concreto, sino una plantilla que pue<strong>de</strong> aplicarse en<br />
muchas situaciones distintas.<br />
�� Consecuencias<br />
Consecuencias.<br />
� Resultados, ventajas e inconvenientes <strong>de</strong> aplicar el patrón.<br />
� P.ej.: relación entre eficiencia en espacio y tiempo; cuestiones <strong>de</strong><br />
implementación implementación, etc etc.<br />
7
<strong>Patrones</strong> <strong>de</strong> <strong>Diseño</strong><br />
<strong>Ejemplo</strong>: MVC <strong>de</strong> Smalltalk<br />
�Mo<strong>de</strong>lo/Vista/Controlador.<br />
C<br />
D<br />
B<br />
A<br />
A B C D<br />
X 60 20 15 5<br />
Y 40 25 15 20<br />
Z 10 10 20 60<br />
Mo<strong>de</strong>lo<br />
A: 40%<br />
B: 25%<br />
CC: 15%<br />
D: 20%<br />
40<br />
30<br />
20<br />
10<br />
0<br />
A B C D<br />
8
<strong>Patrones</strong> <strong>de</strong> <strong>Diseño</strong><br />
<strong>Ejemplo</strong>: MVC <strong>de</strong> Smalltalk<br />
�� SSeparar llos objetos bj t con llos ddatos t ( (mo<strong>de</strong>lo), d l ) sus<br />
visualizaciones (vistas) y el modo en que la interfaz<br />
reacciona ante la entrada al usuario (controlador).<br />
( )<br />
� Separar p estos componentes, p ppara<br />
aumentar la<br />
flexibilidad y reutilización.<br />
� DDesacoplar l vistas i d<strong>de</strong> mo<strong>de</strong>los, d l mediante di un protocolo l d<strong>de</strong><br />
subscripción/notificación.<br />
� Cada vez que cambian los datos <strong>de</strong>l mo<strong>de</strong>lo, avisar a<br />
las vistas que q <strong>de</strong>pen<strong>de</strong>n p<br />
<strong>de</strong> él. Estas se actualizan.<br />
9
<strong>Patrones</strong> <strong>de</strong> <strong>Diseño</strong><br />
<strong>Ejemplo</strong>: MVC <strong>de</strong> Smalltalk<br />
�� Patrón Observer Observer, más general (<strong>de</strong>pen<strong>de</strong>ncias entre<br />
objetos).<br />
� Las vistas se pue<strong>de</strong>n anidar: Vistas compuestas y<br />
simples.<br />
�� Generalización: Patrón Composite Composite.<br />
� La relación entre la vista y el controlador: patrón<br />
St Strategy t ( (un objeto bj t que representa t un algoritmo). l it )<br />
�� Otros patrones:<br />
� Factory Method: especifica la clase controlador pre<strong>de</strong>terminada<br />
para una vista.<br />
�� Decorator: Aña<strong>de</strong> capacidad <strong>de</strong> <strong>de</strong>splazamiento a una vista vista.<br />
10
El catálogo <strong>de</strong> patrones<br />
Ámmbito<br />
Propósito<br />
Creación Estructurales De Comportamiento<br />
Clase Factory Method Adapter (<strong>de</strong> clases) Interpreter.<br />
Template Method. Method<br />
Objeto j Abstract Factory Adapter (<strong>de</strong> objetos). Chain of Responsibility.<br />
Buil<strong>de</strong>r<br />
Bridge.<br />
Command.<br />
Prototype Composite.<br />
Iterator.<br />
Singleton Decorator.<br />
Mediator.<br />
Faca<strong>de</strong>.<br />
Memento.<br />
Flyweight.<br />
Observer.<br />
Proxy. State.<br />
Strategy.<br />
Visitor.<br />
11
El catálogo<br />
<strong>de</strong> patrones<br />
Relaciones entre<br />
los patrones.<br />
12
Indice<br />
�� Introducción<br />
Introducción.<br />
� <strong>Patrones</strong> <strong>de</strong> Creación.<br />
�Singleton<br />
�Singleton.<br />
�Abstract Factory.<br />
�Factory Method.<br />
� <strong>Patrones</strong> Estructurales.<br />
� <strong>Patrones</strong> <strong>de</strong> Comportamiento.<br />
�� Concl Conclusiones. siones<br />
� Bibliografía.<br />
13
<strong>Patrones</strong> <strong>de</strong> Creación<br />
�� Ab Abstraen t el l proceso <strong>de</strong> d instanciación<br />
i t i ió<br />
� Ayudan a que el sistema sea in<strong>de</strong>pendiente <strong>de</strong><br />
cómo se crean crean, componen y representan los<br />
objetos.<br />
� Flexibilizan:<br />
� qué se crea<br />
� quién lo crea<br />
� cómo se crea<br />
� cuándo se crea<br />
�� Permiten configurar un sistema:<br />
� estáticamente (compile-time)<br />
� dinámicamente (run-time) ( )<br />
14
Singleton<br />
�� IIntención. t ió<br />
� Asegurar que una clase tiene una única instancia y proporciona un<br />
punto <strong>de</strong> acceso global a dicha instancia.<br />
� Motivación.<br />
� Hay veces que es importante asegurar que una clase tenga una<br />
sola instancia instancia, por ejemplo:<br />
� Un gestor <strong>de</strong> ventanas<br />
� Una única cola <strong>de</strong> impresión<br />
� Un único sistema <strong>de</strong> ficheros<br />
� Un único fichero <strong>de</strong> log, o un único repositorio.<br />
� ¿Cómo asegurarlo? una variable global hace el objeto<br />
accesible accesible, pero se pue<strong>de</strong> instanciar varias veces veces.<br />
� Responsabilidad <strong>de</strong> la clase misma: actuar sobre el<br />
mensaje <strong>de</strong> creación <strong>de</strong> instancias<br />
15
Singleton<br />
� Aplicabilidad.<br />
� Cuando <strong>de</strong>be haber una sola instancia, y <strong>de</strong>be ser accesible a los<br />
clientes <strong>de</strong>s<strong>de</strong> un punto <strong>de</strong> acceso conocido.<br />
� Cuando la única instancia <strong>de</strong>be ser extensible mediante<br />
subclasificación, y los clientes <strong>de</strong>ben ser capaces <strong>de</strong> usar una<br />
instancia extendida sin modificar su código código.<br />
� Estructura.<br />
Singleton<br />
static Singleton uniqueInstance<br />
singletonData<br />
static Singleton Instance ()<br />
SingletonOperation ()<br />
GetSingletonData ()<br />
return uniqueInstance<br />
16
Singleton<br />
� Participantes: p<br />
� Singleton:<br />
� Define una operación <strong>de</strong> clase, llamada “Instance” que <strong>de</strong>ja a los clientes<br />
acce<strong>de</strong>r a la única instancia.<br />
� Pue<strong>de</strong> ser responsable <strong>de</strong> crear su única instancia.<br />
� Colaboraciones:<br />
� Los clientes acce<strong>de</strong>n a la instancia <strong>de</strong> un Singleton a través <strong>de</strong> la<br />
operación “Instance”.<br />
� Consecuencias:<br />
� Acceso controlado a la única instancia.<br />
� Espacio <strong>de</strong> nombre reducido. Mejora sobre el uso <strong>de</strong> variables<br />
globales.<br />
� Permite el refinamiento <strong>de</strong> operaciones p y la representación. p Se pue<strong>de</strong> p<br />
subclasificar <strong>de</strong> la clase Singleton y configurar la aplicación con una<br />
instancia <strong>de</strong> esta clase.<br />
� Fácil modificación para permitir un número variable <strong>de</strong> instancias.<br />
� Más flexible que las operaciones <strong>de</strong> clase.<br />
17
Singleton<br />
�Implementación:<br />
�Implementación:<br />
class Singleton {<br />
private: p<br />
static Singleton* _instance;<br />
void otherOperations();<br />
protected:<br />
Singleton();<br />
public:<br />
static Singleton* getInstance();<br />
};<br />
Singleton* Singleton::_instance = 0;<br />
Singleton* Singleton::getInstance() {<br />
if (_instance == 0 )<br />
_instance instance = new Singleton;<br />
return _instance;<br />
}<br />
18
#inclu<strong>de</strong> "stdafx.h"<br />
#inclu<strong>de</strong> <br />
using namespace std;<br />
class Maze{<br />
int x, y;<br />
public:<br />
};<br />
M Maze(int (i x, i int y) ) : x(x), ( ) y(y) ( ) {}<br />
class MazeFactory {<br />
public: bli<br />
static MazeFactory* Instance();<br />
// existing interface goes here<br />
Maze * createMaze(int x, int y) { return new Maze(x, y); };<br />
protected: t t d<br />
MazeFactory() {};<br />
private:<br />
static MazeFactory* _instance;<br />
};<br />
MazeFactory* MazeFactory::_instance = 0;<br />
MMazeFactory* F t * MazeFactory::Instance M F t I t () {<br />
if (_instance == 0) _instance = new MazeFactory;<br />
return _instance;<br />
}<br />
void main(){<br />
Maze * m = MazeFactory::Instance()->createMaze(10,10);<br />
}<br />
<strong>Ejemplo</strong><br />
19
Singleton<br />
� Implementación:<br />
� Creación <strong>de</strong> una subclase <strong>de</strong> singleton.<br />
�� DDeterminar t i qué é singleton i l t queremos usar en lla operación ió “I “Instance”. t ”<br />
� Registro <strong>de</strong> objetos singleton.<br />
class Singleton {<br />
public:<br />
static void Register(const char* name, Singleton*);<br />
static Singleton* Singleton Instance();<br />
protected:<br />
static Singleton* Lookup(const char* name);<br />
private:<br />
static Singleton* _instance;<br />
static List* _registry;<br />
};<br />
Si Singleton* l t * Si Singleton::Instance l t I t () {<br />
if (_instance == 0) {<br />
const char* singletonName =getenv("SINGLETON");<br />
// user use oor eenvironment o e supp supplies es this s aat sstartup a up<br />
_instance = Lookup(singletonName); // Lookup returns 0 if there's no such singleton<br />
}<br />
return _instance; }<br />
20
Singleton<br />
� ¿Dón<strong>de</strong> se registra la clase?<br />
� Una posibilidad es en el constructor.<br />
MySingleton::MySingleton() {<br />
// ...<br />
Singleton::Register("MySingleton", g g ( y g this); )<br />
}<br />
�Entonces hay que instanciar la clase!<br />
�Se pue<strong>de</strong> crear una instancia global:<br />
static MySingleton theSingleton;<br />
21
Singleton g<br />
<strong>Ejemplo</strong><br />
class MazeFactory {<br />
public:<br />
static MazeFactory* Instance();<br />
// existing g interface ggoes<br />
here<br />
protected:<br />
MazeFactory();<br />
private:<br />
static MazeFactory MazeFactory* _instance; instance;<br />
};<br />
MazeFactory* MazeFactory::_instance = 0;<br />
MazeFactory* MazeFactory MazeFactory::Instance () {<br />
if (_instance == 0) {<br />
const char* mazeStyle = getenv("MAZESTYLE");<br />
if (strcmp(mazeStyle, "bombed") == 0)<br />
_instance i t = new BBombedMazeFactory; b dM F t<br />
} else if (strcmp(mazeStyle, "enchanted") == 0)<br />
_instance = new EnchantedMazeFactory;<br />
// ... other possible subclasses<br />
} else<br />
_instance = new MazeFactory;<br />
return _instance;<br />
}<br />
22
Abstract Factory<br />
�� PPropósito. ó it<br />
� Proporciona una interfaz para crear familias <strong>de</strong> objetos<br />
relacionados o que <strong>de</strong>pen<strong>de</strong>n entre sí, sin especificar sus<br />
clases l concretas.<br />
� También Conocido Como.<br />
�� Kit Kit.<br />
� Motivación.<br />
� Ej.: un framework para la construcción <strong>de</strong> interfaces <strong>de</strong> usuario<br />
que permita varios “ “look and f feel” ” ( (ej.: Motiff y Presentation<br />
Manager).<br />
� Una clase abstracta WidgetFactory con la interfaz para crear<br />
cada tipo <strong>de</strong> widget widget.<br />
� Una clase abstracta para cada tipo <strong>de</strong> widget. Subclases<br />
concretas que implementan cada widget concreto.<br />
�� De esta manera manera, los clientes son in<strong>de</strong>pendientes <strong>de</strong>l look<br />
and feel concreto.<br />
23
Abstract Factory<br />
� Motivación.<br />
WidgetFactory<br />
CreateScrollBar()<br />
CreateWindow()<br />
MotifWidgetFactory PMWindowFactory<br />
CreateScrollBar()<br />
CreateWindow()<br />
Familias<br />
CreateScrollBar()<br />
CreateWindow()<br />
PMWindow<br />
PMScrollBar<br />
Productos<br />
Window<br />
MotifWindow<br />
ScrollBar<br />
MotifScrollBar<br />
Client<br />
24
Abstract Factory<br />
� Aplicabilidad. Usar este patrón cuando:<br />
�un sistema que <strong>de</strong>ba ser in<strong>de</strong>pendiente <strong>de</strong> cómo se<br />
crean, componen y representan sus productos. d<br />
�un sistema que <strong>de</strong>ba ser configurado con una familia <strong>de</strong><br />
productos entre varias varias.<br />
�una familia <strong>de</strong> objetos producto relacionados que está<br />
diseñada para ser usada conjuntamente conjuntamente, y es necesario<br />
hacer cumplir esta restricción.<br />
�se quiere q proporcionar p p una biblioteca <strong>de</strong> clases<br />
productos, y sólo se quiere revelar sus interfaces, no su<br />
implementación.<br />
25
Abstract Factory<br />
�Estructura:<br />
ConcreteFactory1<br />
AbstractFactory<br />
Productos<br />
createProductA ()<br />
createProductB () AbstractProductA<br />
Familias<br />
ConcreteFactory2<br />
createProductA () createProductA ()<br />
createProductB () createProductB ()<br />
ProductA2<br />
ProductA1<br />
AbstractProductB<br />
ProductB2<br />
ProductB1<br />
Client<br />
26
Abstract Factory<br />
� Participantes: p<br />
� AbstractFactory. Declara una interfaz para operaciones que<br />
crean objetos producto abstractos.<br />
� ConcreteFactory. y Implementa p las operaciones p para p crear objetos j<br />
producto concretos.<br />
� AbstractProduct. Declara una interfaz para un tipo <strong>de</strong> objeto<br />
producto.<br />
� ConcreteProduct. Define un objeto producto para que sea creado<br />
por la fábrica correspondiente.<br />
� Client. Sólo usa interfaces <strong>de</strong>claradas por las clases<br />
Ab AbstractFactory t tF t y Ab AbstractProduct.<br />
t tP d t<br />
� Colaboraciones.<br />
� Normalmente sólo se crea una única instancia <strong>de</strong> una clase<br />
ConcreteFactory en tiempo <strong>de</strong> ejecución. Esta fábrica concreta<br />
crea objetos producto que tienen una <strong>de</strong>terminada<br />
implementación.<br />
�� Ab AbstractFactory t tF t d<strong>de</strong>lega l lla creación ió d<strong>de</strong> objetos bj t producto d t en su<br />
subclase ConcreteFactory.<br />
27
Abstract Factory<br />
�Consecuencias.<br />
C i<br />
�Aísla las clases concretas. Ayuda a controlar<br />
las clases <strong>de</strong> objetos que crea una aplicación.<br />
Aísla a los clientes <strong>de</strong> las clases <strong>de</strong><br />
implementación<br />
implementación.<br />
�Facilita el reemplazo <strong>de</strong> familias <strong>de</strong> productos.<br />
�P �Promueve lla consistencia i t i entre t productos d t ( (que<br />
la aplicación use objetos <strong>de</strong> una sola familia a<br />
la vez) vez).<br />
�Es difícil añadir un nuevo producto.<br />
28
Abstract Factory<br />
<strong>Ejemplo</strong><br />
� <strong>Ejemplo</strong>: aplicación para construir uncocheapartir<br />
<strong>de</strong> unas partes (motor, chasis, ...)<br />
� ttodos d llos componentes t d<strong>de</strong> lla misma i marca (f (familia) ili )<br />
� hay múltiples marcas (Ford, Toyota, Opel, ...)<br />
� es responsabilidad p <strong>de</strong>l cliente ensamblar las piezas p<br />
CarEngine<br />
CarPart<br />
FordEngine ToyotaEngine PorscheEngine<br />
Car<br />
FordCar ToyotaCar PorscheCar<br />
CarBody<br />
FordBody ToyotaBody PorscheBody<br />
29
Abstract Factory<br />
<strong>Ejemplo</strong> (ii)<br />
� � ¿Cómo lo haríamos sin utilizar el patrón Abstract Factory?<br />
En un método <strong>de</strong>l cliente:<br />
CrearCoche (string marca) {<br />
}<br />
if (marca == “ford”)<br />
FordCar coche = new FordCar ()<br />
else if (marca == “toyota”)<br />
ToyotaCar coche = new ToyotaCar ()<br />
else …;<br />
if (marca == “ford”)<br />
FordEngine motor = new FordEngine ()<br />
else if (marca == “toyota”)<br />
ToyotaEngine motor = new ToyotaEngine ()<br />
else …;<br />
coche.add (motor);<br />
...<br />
return coche;<br />
El código <strong>de</strong>l cliente<br />
<strong>de</strong>ci<strong>de</strong> qué clase <strong>de</strong><br />
coche construir (bien)<br />
y qué subpartes<br />
instanciar (mal). Pue<strong>de</strong><br />
cometerse el error <strong>de</strong><br />
ensamblar partes <strong>de</strong><br />
distintas familias familias.<br />
30
Abstract Factory<br />
<strong>Ejemplo</strong> (iii)<br />
ToyotaFactory<br />
makeCar ()<br />
makeBody ()<br />
makeEngine ()<br />
CarPartFactory<br />
makeCar ()<br />
makeBody y() ()<br />
makeEngine ()<br />
Familias<br />
FordFactory<br />
FordBody<br />
Productos<br />
CarBody<br />
CarEngine<br />
ToyotaBody<br />
makeCar ()<br />
makeBody ()<br />
makeEngine () FordEngine ToyotaEngine<br />
FordCar<br />
Car<br />
ToyotaCar<br />
Client<br />
31
Abstract Factory<br />
<strong>Ejemplo</strong> (iv)<br />
� Utilizando el patrón, éste fuerza a que todos los productos sean <strong>de</strong> la<br />
misma familia, una vez establecida ésta por el cliente.<br />
� El patrón permite separar la elección <strong>de</strong> la familia (la marca <strong>de</strong>l<br />
coche) <strong>de</strong>l proceso <strong>de</strong> instanciar las partes.<br />
� En el cliente:<br />
Car hacerCoche () {<br />
Car coche=familia.makeCar();<br />
coche.addEngine (familia.makeEngine());<br />
coche.addBody (familia.makeBody ());<br />
...<br />
return t coche; h<br />
}<br />
32
Abstract Factory<br />
<strong>Ejemplo</strong> (v)<br />
�� familia contiene una instancia <strong>de</strong> una marca <strong>de</strong> coche coche.<br />
� ¿Cómo se instancia familia?<br />
//presenta por pantalla la selección<br />
class CrearCocheGUI : public CFrameWnd {<br />
//….<br />
void id OOnButtonClicked B tt Cli k d () {<br />
string familiasel;<br />
CrearCoche assembler;<br />
Car coche;<br />
// //…<br />
if (familiasel == “ford”)<br />
assembler=CrearCoche::using (new FordFactory())<br />
else if (familiasel == “toyota”)<br />
assembler=CrearCoche::using bl C C h i ( (new TToyotaFactory()) t F t ())<br />
else …;<br />
coche = assembler.hacerCoche();<br />
}<br />
}<br />
class CrearCoche {<br />
CarPartFactory y * familia; ;<br />
Car hacerCoche () {<br />
Car coche=familia->makeCar();<br />
coche.addEngine g ( (familia->makeEngine()); g ());<br />
coche.addBody (familia->makeBody ());<br />
...<br />
return coche;<br />
}<br />
static CrearCoche using (CarPartFactory * f) {<br />
CrearCoche l;<br />
l.factory y(); (f);<br />
return l;<br />
}<br />
void factory y( (CarPartFactory y * f) ){ {<br />
familia=f;<br />
}<br />
}<br />
33
Abstract Factory<br />
Otro <strong>Ejemplo</strong>: Laberinto<br />
MazeFactory<br />
+MakeMaze(): Maze<br />
+MakeWall(): Wall<br />
+MakeRoom(int n): Room<br />
+MakeDoor(Room r1, Room r2): Door<br />
EnchantedMazeFactory<br />
+MakeRoom(int n): EnchantedRoom<br />
+MakeDoor(Room r1, Room r2):<br />
DoorNeedingSpell<br />
BombedMazeFactory<br />
+MakeRoom(int n): RoomWithABomb<br />
+MakeWall(): BombedWall<br />
MazeGame<br />
+CreateMaze(MazeFactory): Maze<br />
Maze Wall Room<br />
Door<br />
DoorNeeding<br />
Spell<br />
Bombed<br />
Wall<br />
Enchanted<br />
Room<br />
RoomWithA<br />
Bomb<br />
34
Abstract Factory<br />
Otro <strong>Ejemplo</strong>: Laberinto<br />
class MazeFactory {<br />
public:<br />
MazeFactory();<br />
virtual it lM Maze* *MMakeMaze() k M () const t<br />
{ return new Maze; }<br />
virtual Wall* MakeWall() const<br />
{ return new Wall; ; }<br />
virtual Room* MakeRoom(int n) const<br />
{ return new Room(n); }<br />
virtual Door* MakeDoor(Room* r1, Room* r2) const<br />
{ return t new Door(r1, D ( 1 r2); 2) }<br />
};<br />
35
Abstract Factory<br />
Otro <strong>Ejemplo</strong><br />
Maze* MazeGame::CreateMaze (MazeFactory& factory) {<br />
Maze* aMaze = factory.MakeMaze();<br />
Room* Room r1 = factory.MakeRoom(1);<br />
Room* r2 = factory.MakeRoom(2);<br />
Door* aDoor = factory.MakeDoor(r1, r2);<br />
aMaze->AddRoom(r1);<br />
aMaze->AddRoom(r2);<br />
M AddR ( 2)<br />
r1->SetSi<strong>de</strong>(North, factory.MakeWall());<br />
r1->SetSi<strong>de</strong>(East, aDoor);<br />
r1->SetSi<strong>de</strong>(South, ( , factory.MakeWall());<br />
y ());<br />
r1->SetSi<strong>de</strong>(West, factory.MakeWall());<br />
r2->SetSi<strong>de</strong>(North, factory.MakeWall());<br />
r2->SetSi<strong>de</strong>(East, factory.MakeWall());<br />
r2->SetSi<strong>de</strong>(South, 2 >S tSid (S th factory.MakeWall());<br />
f t M k W ll())<br />
r2->SetSi<strong>de</strong>(West, aDoor);<br />
return aMaze;<br />
}<br />
36
Abstract Factory<br />
Otro <strong>Ejemplo</strong><br />
class EnchantedMazeFactory : public MazeFactory {<br />
public:<br />
EnchantedMazeFactory();<br />
virtual Room* MakeRoom(int n) const<br />
{ return new EnchantedRoom(n, CastSpell()); }<br />
virtual Door* MakeDoor(Room* r1, Room* r2) const<br />
{ return new DoorNeedingSpell(r1, g p ( , r2); );<br />
}<br />
protected:<br />
Spell* CastSpell() const;<br />
};<br />
// Make it possible to have rooms with bombs<br />
Wall* Wall BombedMazeFactory::MakeWall () const {<br />
return new BombedWall;<br />
}<br />
Room* BombedMazeFactory::MakeRoom(int n) const {<br />
return t new RoomWithABomb(n);<br />
R WithAB b( )<br />
}<br />
MazeGame game;<br />
BombedMazeFactory y factory; y;<br />
game.CreateMaze(factory);<br />
37
Factory Method<br />
�� PPropósito. ó it<br />
� Define una interfaz para crear un objeto, pero <strong>de</strong>ja que<br />
sean las subclases quienes q <strong>de</strong>cidan qué q clase instanciar.<br />
Permite que una clase <strong>de</strong>legue en sus subclases la<br />
creación <strong>de</strong> objetos.<br />
�� También Conocido Como.<br />
� Virtual Constructor.<br />
� Motivación.<br />
� Ej.: un framework que pueda presentar distintos tipos <strong>de</strong><br />
documentos (similar a MFCs).<br />
�Dos abstracciones clave: aplicación p y documento (ambas (<br />
clases abstractas). Hay que subclasificarlas.<br />
�La clase aplicación no sabe qué subclase documento<br />
instanciar.<br />
38
Factory Method<br />
� Motivación.<br />
Documento<br />
+Abrir() b ()<br />
+Cerrar()<br />
+Guardar()<br />
+Deshacer()<br />
MiDocumento<br />
docs<br />
1..*<br />
Aplicacion<br />
+CrearDocumento()<br />
CrearDocumento()<br />
+NuevoDocumento()<br />
+AbrirDocumento()<br />
MiAplicacion<br />
+CrearDocumento()<br />
C D t ()<br />
Se le llama “factory method” (método<br />
<strong>de</strong> fabricación)<br />
Documento * doc = CrearDocumento()<br />
ddocs.push_back(doc) h b k(d )<br />
doc->Abrir()<br />
return new MiDocumento<br />
39
Factory Method<br />
� AAplicabilidad. li bilid d UUsar este patrón ó cuando: d<br />
� Una clase no pue<strong>de</strong> prever la clase <strong>de</strong> los objetos que tiene que crear.<br />
�� Una clase quiere que sean sus subclases las que <strong>de</strong>cidan qué objetos<br />
crean.<br />
� Las clases <strong>de</strong>legan la responsabilidad en una <strong>de</strong> entre varias clases<br />
auxiliares auxiliares, y queremos localizar qué subclase concreta es en la que se<br />
<strong>de</strong>lega.<br />
� Estructura.<br />
PProduct d t<br />
Creator<br />
+FactoryMethod()<br />
+AnOperation()<br />
CConcreteProduct t P d t CConcreteCreator t C t<br />
+FactoryMethod()<br />
//…<br />
product = factoryMethod()<br />
//…<br />
return new ConcreteProduct<br />
40
Factory Method<br />
�� PParticipantes. ti i t<br />
� Product (Documento). Define la interfaz <strong>de</strong> los objetos que crea<br />
el factoryy method.<br />
� ConcreteProduct (MiDocumento). Implementa la interfaz <strong>de</strong>l<br />
producto.<br />
�� Creator (Aplicacion) (Aplicacion). Declara el factory method method. Pue<strong>de</strong> también<br />
dar una implementación por <strong>de</strong>fecto <strong>de</strong>l factory method, que<br />
<strong>de</strong>vuelve un objeto <strong>de</strong> una clase por <strong>de</strong>fecto.<br />
�� ConcreteCreator (MiAplicacion) (MiAplicacion). Sobreescribe el factory<br />
method para <strong>de</strong>volver una instancia <strong>de</strong> ConcreteProduct.<br />
� Colaboraciones.<br />
� El creator se apoya en sus subclases para <strong>de</strong>finir el método <strong>de</strong><br />
fabricación <strong>de</strong> manera que éste <strong>de</strong>vuelva una instancia <strong>de</strong>l<br />
ConcreteProduct a<strong>de</strong>cuado.<br />
41
Factory Method<br />
�� Consecuencias<br />
Consecuencias.<br />
�Los métodos <strong>de</strong> fabricación eliminan la necesidad <strong>de</strong><br />
ligar g clases específicas p <strong>de</strong> la aplicación p a nuestro<br />
código.<br />
�El �El código sólo trata con la interfaz Product Product, pue<strong>de</strong><br />
funcionar con cualquier clase ConcreteProduct<br />
<strong>de</strong>finida por el usuario.<br />
�Proporciona enganches para las subclases. Crear<br />
objetos con un método <strong>de</strong> fabricación es más flexible<br />
que hacerlos directamente.<br />
�El �El ffactory t method th d es un hhook k method th d para que llas<br />
subclases <strong>de</strong>n una versión extendida <strong>de</strong>l código.<br />
42
Factory Method<br />
�Consecuencias.<br />
Figure Manipulator<br />
…<br />
+DownClick()<br />
+CreateManipulator() p ()<br />
+Drag() g()<br />
…<br />
+UpClick()<br />
LineFigure<br />
TextFigure<br />
LineManipulator<br />
…<br />
…<br />
+DownClick()<br />
+CreateManipulator() +CreateManipulator() +Drag()<br />
+UpClick()<br />
TextManipulator<br />
+DownClick()<br />
+Drag()<br />
+UpClick()<br />
43
Factory Method<br />
�Implementación.<br />
I l t ió<br />
�Dos variantes principales:<br />
� Cuando la clase Creator es abstracta y no<br />
proporciona implementación para el método <strong>de</strong><br />
fabricación que <strong>de</strong>clara <strong>de</strong>clara.<br />
�Cuando la clase Creator es concreta y proporciona<br />
una implementación pre<strong>de</strong>terminada para el método<br />
<strong>de</strong> fabricación.<br />
�Métodos <strong>de</strong> fabricación parametrizados:<br />
�Que Q llos ffactory t methods th d creen varios i ti tipos d<strong>de</strong><br />
producto. El método recibe un parámetro que<br />
i<strong>de</strong>ntifica el tipo p <strong>de</strong>objeto j<br />
a crear.<br />
44
Factory Method<br />
�Implementación.<br />
class Creator {<br />
public:<br />
Product* GetProduct();<br />
protected:<br />
virtual Product* CreateProduct(); // factory method<br />
private:<br />
Product* _product;<br />
};<br />
Product* Creator::GetProduct () {<br />
if (_product ( d t == 0) {<br />
_product = CreateProduct();<br />
}<br />
ret return rn _product; prod ct<br />
}<br />
45
Factory Method<br />
� Implementación. Se pue<strong>de</strong>n usar plantillas para evitar<br />
la herencia (múltiples subclases <strong>de</strong> Creator).<br />
class Creator {<br />
public:<br />
virtual Product* CreateProduct() = 0;<br />
// pure virtual factory method<br />
};<br />
template <br />
class StandardCreator: public Creator {<br />
public:<br />
virtual TheProduct* CreateProduct();<br />
};<br />
template <br />
TheProduct*<br />
StandardCreator::CreateProduct () {<br />
return new TheProduct;<br />
}<br />
// El cliente proporciona sólo la clase <strong>de</strong>l<br />
// producto, no necesita hacer una<br />
// nueva clase que here<strong>de</strong> <strong>de</strong> creator.<br />
class MyProduct : public Product {<br />
public:<br />
MyProduct();<br />
// ...<br />
};<br />
StandardCreator myCreator;<br />
46
Factory Method<br />
<strong>Ejemplo</strong><br />
class MazeGame {<br />
public:<br />
Maze* CreateMaze(); ();<br />
// factory methods:<br />
virtual Maze* MakeMaze() const<br />
{ return new Maze; }<br />
virtual Room* MakeRoom(int n) const<br />
{ return new Room(n); }<br />
virtual Wall* MakeWall() const<br />
{ return new Wall; }<br />
virtual Door* MakeDoor(Room* r1, Room* r2) const<br />
{ return new Door(r1, r2); }<br />
};<br />
Maze* MazeGame::CreateMaze () {<br />
Maze* aMaze = MakeMaze();<br />
Room* Room r1 = MakeRoom(1);<br />
Room* r2 = MakeRoom(2);<br />
Door* theDoor = MakeDoor(r1, r2);<br />
aMaze->AddRoom(r1);<br />
aMaze->AddRoom(r2);<br />
M AddR ( 2)<br />
r1->SetSi<strong>de</strong>(North, MakeWall());<br />
r1->SetSi<strong>de</strong>(East, theDoor);<br />
r1->SetSi<strong>de</strong>(South, ( , MakeWall()); ());<br />
r1->SetSi<strong>de</strong>(West, MakeWall());<br />
r2->SetSi<strong>de</strong>(North, MakeWall());<br />
r2->SetSi<strong>de</strong>(East, MakeWall());<br />
r2->SetSi<strong>de</strong>(South, 2 >S tSid (S th MakeWall());<br />
M k W ll())<br />
r2->SetSi<strong>de</strong>(West, theDoor);<br />
return aMaze;<br />
}<br />
47
Factory Method<br />
<strong>Ejemplo</strong><br />
class BombedMazeGame : public MazeGame {<br />
public:<br />
BombedMazeGame();<br />
virtual Wall* Wall MakeWall() const<br />
{ return new BombedWall; }<br />
virtual Room* MakeRoom(int n) const<br />
{ return new RoomWithABomb(n); }<br />
};<br />
class EnchantedMazeGame : public MazeGame {<br />
public: bli<br />
EnchantedMazeGame();<br />
virtual Room* MakeRoom(int n) const<br />
{ return new EnchantedRoom(n, ( , CastSpell()); p ()); }<br />
virtual Door* MakeDoor(Room* r1, Room* r2) const<br />
{ return new DoorNeedingSpell(r1, r2); }<br />
protected:<br />
SSpell* ll* CCastSpell() tS ll() const; t<br />
};<br />
48
Indice<br />
�� IIntroducción. t d ió<br />
� <strong>Patrones</strong> <strong>de</strong> Creación.<br />
�<strong>Patrones</strong> P t EEstructurales. t t l<br />
�Composite.<br />
Co pos te<br />
�Faca<strong>de</strong>.<br />
�Pro �Proxy.<br />
�Adapter.<br />
� <strong>Patrones</strong> <strong>de</strong> Comportamiento.<br />
� Conclusiones.<br />
� Bibliografía.<br />
49
<strong>Patrones</strong> Estructurales<br />
� Etbl Establecen cómo ó se componen clases l y objetos bj t<br />
para formar estructuras mayores que<br />
implementan nueva funcionalidad<br />
funcionalidad.<br />
� Los patrones <strong>de</strong> clase usan la herencia para<br />
componer interfaces o implementaciones (ej (ej.: :<br />
Adapter).<br />
�� Los patrones <strong>de</strong> objeto objeto, <strong>de</strong>scriben maneras <strong>de</strong><br />
componer objetos para implementar nueva<br />
funcionalidad<br />
funcionalidad.<br />
� Flexibilidad, ya que se pue<strong>de</strong> cambiar la configuración<br />
en tiempo <strong>de</strong> ejecución.<br />
50
Composite<br />
� Propósito.<br />
� componer objetos en estructuras arborescentes para<br />
representar jerarquías parte-conjunto.<br />
�� MMotivación. ti ió<br />
Linea<br />
dibuja ()<br />
� Aplicaciones gráficas. Manipulación <strong>de</strong> grupos <strong>de</strong> figuras <strong>de</strong><br />
manera uniforme uniforme.<br />
Rectangulo<br />
dibuja ()<br />
Grafico<br />
dibuja ()<br />
Texto<br />
dibuja ()<br />
*<br />
graficos<br />
Dibujo<br />
dibuja ()<br />
aña<strong>de</strong> (Grafico g)<br />
elimina (Grafico g)<br />
obtenHijo (int)<br />
para todo g en graficos<br />
g.dibuja ()<br />
añadir g a la lista <strong>de</strong><br />
graficos:<br />
graficos.addElement (g)<br />
51
Composite<br />
�� Una instancia en tiempo <strong>de</strong> ejecución:<br />
graficos<br />
:Dibujo<br />
:Dibujo<br />
graficos graficos graficos<br />
graficos<br />
:Rectangulo :Texto<br />
:Linea :Texto
Composite<br />
� Aplicabilidad. Usar el patrón cuando:<br />
� Se quieren representar jerarquías todo/parte <strong>de</strong> objetos.<br />
� Se quiere que los clientes ignoren la diferencia entre composiciones <strong>de</strong><br />
objetos j y objetos j individuales. Los clientes tratarán todos los objetos j en<br />
la estructura compuesta <strong>de</strong> manera uniforme.<br />
� Estructura.<br />
Client Component<br />
+ Operation()<br />
+ Add(Component)<br />
( p )<br />
+ Remove(Component)<br />
+ GetChild(int)<br />
Leaf<br />
+ Operation()<br />
*<br />
children<br />
Composite<br />
+ Operation() p ()<br />
+ Add(Component)<br />
+ Remove(Component)<br />
+ GetChild(int)<br />
forall g in children:<br />
g.Operation()<br />
O ti ()<br />
53
Composite<br />
� Participantes. p<br />
� Component (Grafico).<br />
� Declara la interfaz <strong>de</strong> los objetos <strong>de</strong> la composición.<br />
� Implementa p el comportamiento p por p <strong>de</strong>fecto <strong>de</strong> la interfaz común a<br />
todas las clases.<br />
� Declara las interfaces para acce<strong>de</strong>r y gestionar los hijos.<br />
� (opcional) Define una interfaz para acce<strong>de</strong>r al padre <strong>de</strong> un componente<br />
en la estructura recursiva y la implementa implementa, si es apropiado apropiado.<br />
� Leaf (Linea, Rectangulo, …).<br />
� Representa objetos hoja en la composición. Una hoja no tiene hijos.<br />
�� Define el comportamiento <strong>de</strong> los objetos primitivos en la composición<br />
composición.<br />
� Composite (Dibujo)<br />
� Define el comportamiento <strong>de</strong> los objetos con hijos en la composición.<br />
�� Almacena componentes hijo hijo.<br />
� Implementa operaciones relacionadas con los hijos <strong>de</strong> la interfaz <strong>de</strong><br />
Component.<br />
�� Client Client.<br />
� Manipula objetos en la composición a través <strong>de</strong> la interfaz <strong>de</strong><br />
54<br />
Component.
Composite<br />
�� Colaboraciones<br />
Colaboraciones.<br />
� Los clientes usan el interfaz <strong>de</strong> la clase Component para<br />
interaccionar con los objetos <strong>de</strong> la estructura compuesta.<br />
�� Si ell objeto bj t eshoja, h j entonces t lla petición ti ió secursadirectamente.<br />
di t t<br />
� Si el objeto es un Composite, entonces normalmente redirige las<br />
peticiones a sus objetos hijo, quizá realizando operaciones<br />
adicionales antes y/o <strong>de</strong>spués <strong>de</strong> la redirección.<br />
� Consecuencias. El patron composite:<br />
�� Define jerarquías <strong>de</strong> objetos primitivos y compuestos compuestos. Cuando<br />
un código cliente espera un objeto simple, se pue<strong>de</strong> reemplazar<br />
por uno compuesto.<br />
�� Simplifica el cliente cliente. Se pue<strong>de</strong>n tratar objetos simples y<br />
compuestos <strong>de</strong> manera uniforme.<br />
� Facilita añadir nuevos tipos <strong>de</strong> componente.<br />
� Pue<strong>de</strong> hacer el diseño <strong>de</strong>masiado general. Complicado restringir<br />
los tipos <strong>de</strong> componente <strong>de</strong> un composite.<br />
55
Composite<br />
�� IImplementación. l t ió Al Algunas d<strong>de</strong>cisiones: i i<br />
� Referencias explícitas a los padres. En la clase component.<br />
�� Compartir componentes. Útil para ahorrar memoria, pero la<br />
gestión <strong>de</strong> un componente que tiene más <strong>de</strong> un padre es difícil.<br />
� Maximizar la interfaz <strong>de</strong>l componente.<br />
�� Declaración <strong>de</strong> las operaciones <strong>de</strong> gestión <strong>de</strong> hijos hijos. Equilibrio<br />
entre seguridad y transparencia:<br />
� Declararla en la raíz da transparencia. Es menos seguro porque el<br />
cliente pue<strong>de</strong> tratar <strong>de</strong> hacer cosas sin sentido sobre objetos hoja hoja.<br />
� Declararla en la clase compuesto da seguridad, pero per<strong>de</strong>mos<br />
transparencia: leafs y composites tienen interfaces distintas.<br />
�� A veces es necesario tener en cuenta un or<strong>de</strong>n para los hijos hijos.<br />
� ¿Quién <strong>de</strong>be borrar los componentes?<br />
� ¿Cuál es la mejor estructura <strong>de</strong> datos para almacenar los<br />
componentes?.<br />
?<br />
56
Composite<br />
<strong>Ejemplo</strong><br />
class Equipment {<br />
public:<br />
virtual ~Equipment();<br />
const char* Name() { return _name; }<br />
virtual it lWWatt ttP Power(); ()<br />
virtual Currency NetPrice();<br />
virtual Currency DiscountPrice();<br />
virtual void Add(Equipment*);<br />
Add(Equipment );<br />
virtual void Remove(Equipment*);<br />
virtual Iterator* CreateIterator() {return 0;}<br />
protected:<br />
EEquipment(const i t( t char*); h *)<br />
private:<br />
};<br />
const char* _name;<br />
57
Composite<br />
<strong>Ejemplo</strong><br />
class FloppyDisk : public Equipment {<br />
public: p<br />
FloppyDisk(const char*);<br />
virtual ~FloppyDisk();<br />
virtual Watt Power();<br />
virtual Currency NetPrice();<br />
virtual Currency DiscountPrice();<br />
};<br />
class CompositeEquipment : public Equipment {<br />
public:<br />
virtual ~CompositeEquipment();<br />
virtual Watt Power(); ();<br />
virtual Currency NetPrice();<br />
virtual Currency DiscountPrice();<br />
virtual void Add(Equipment*);<br />
virtual void Remove(Equipment*);<br />
virtual Iterator* CreateIterator();<br />
protected:<br />
CompositeEquipment(const p q p ( char*); )<br />
private:<br />
List _equipment;<br />
};<br />
58
Composite<br />
<strong>Ejemplo</strong><br />
Currency CompositeEquipment::NetPrice () {<br />
Iterator* i = CreateIterator();<br />
Currency total = 0;<br />
for (i->First(); (i >First(); !i->IsDone(); !i >IsDone(); i i->Next()) >Next()) {<br />
}<br />
total += i->CurrentItem()->NetPrice();<br />
}<br />
<strong>de</strong>lete i;<br />
return total;<br />
class Chassis : public CompositeEquipment {<br />
public:<br />
Chassis(const char*);<br />
virtual ~Chassis();<br />
};<br />
virtual it lWWatt ttP Power(); ()<br />
virtual Currency NetPrice();<br />
virtual Currency DiscountPrice();<br />
59
Composite<br />
<strong>Ejemplo</strong><br />
using namespace std;<br />
void main()<br />
{<br />
Cabinet* cabinet = new Cabinet("PC Cabinet");<br />
Chassis* chassis = new Chassis( Chassis("PC PC Chassis Chassis"); );<br />
cabinet->Add(chassis);<br />
Bus* bus = new Bus("MCA Bus");<br />
}<br />
bus->Add(new ( Card("16Mbs ( Token Ring")); g ))<br />
chassis->Add(bus);<br />
chassis->Add(new FloppyDisk("3.5in Floppy"));<br />
cout
Faca<strong>de</strong><br />
� Propósito.<br />
� Proporciona p una interfaz unificada paraunconjunto p j <strong>de</strong> interfaces <strong>de</strong> un<br />
subsistema.<br />
� Define una interfaz <strong>de</strong> alto nivel que hace que el subsistema sea más fácil<br />
<strong>de</strong> usar.<br />
� Motivación.<br />
� Estructurar un sistema en subsistemas ayuda a reducir su complejidad.<br />
�� Un objetivo típico <strong>de</strong> diseño es minimizar la comunicación y <strong>de</strong>pen<strong>de</strong>ncias<br />
entre subsistemas.<br />
� Un modo <strong>de</strong> conseguir esto es introducir un objeto fachada que<br />
proporcione una interfaz única y simplificada a los servicios más generales<br />
<strong>de</strong>l subsistema.<br />
61
Faca<strong>de</strong><br />
� Motivación.<br />
62
Faca<strong>de</strong><br />
� Aplicabilidad. Usar el patrón cuando:<br />
� Queramos proporcionar una interfaz simple a un subsistema complejo.<br />
Sólo los clientes que necesitan más personalización necesitarán ir más<br />
allá <strong>de</strong> la fachada.<br />
� Haya muchas <strong>de</strong>pen<strong>de</strong>ncias entre los clientes y las clases que<br />
implementan una abstracción. La fachada <strong>de</strong>sacopla el subsistema <strong>de</strong><br />
sus clientes y otros subsistemas (mejora acoplamiento y portabilidad).<br />
� Queramos dividir en capas nuestros subsistemas. La fachada es el<br />
punto <strong>de</strong> entrada a cada subsistema.<br />
�� EEstructura. t t<br />
63
Faca<strong>de</strong><br />
�� Participantes<br />
Participantes.<br />
� Faca<strong>de</strong> (Compiler).<br />
� Sabe qué clases <strong>de</strong>l subsistema son las responsables ante una<br />
petición petición.<br />
� Delega las peticiones <strong>de</strong> los clientes en los objetos apropiados <strong>de</strong>l<br />
subsistema.<br />
�� Clases <strong>de</strong>l Subsistema (Scanner (Scanner, Parser Parser, ProgramNo<strong>de</strong>Buil<strong>de</strong>r<br />
ProgramNo<strong>de</strong>Buil<strong>de</strong>r,<br />
Co<strong>de</strong>Generator).<br />
� Implementan la funcionalidad <strong>de</strong>l subsistema.<br />
� Realizan las labores encomendadas por p el objeto j Faca<strong>de</strong>.<br />
� No tienen referencias al objeto Faca<strong>de</strong>.<br />
� Observaciones.<br />
�� Los clientes se comunican en el sistema enviando peticiones al<br />
objeto Faca<strong>de</strong>, que las reenvía a los objetos apropiados.<br />
� Los clientes que usan la fachada no tienen que acce<strong>de</strong>r<br />
directamente a los objetos <strong>de</strong>l subsistema.<br />
64
Faca<strong>de</strong><br />
�� CConsecuencias. i<br />
� Oculta a los clientes los componentes <strong>de</strong>l sistema, haciendo<br />
el sistema más fácil <strong>de</strong> usar.<br />
� Promueve acoplamiento débil entre el subsistema y sus<br />
clientes.<br />
�� Elimina <strong>de</strong>pen<strong>de</strong>ncias y pue<strong>de</strong> reducir el tiempo <strong>de</strong><br />
compilación.<br />
� No impi<strong>de</strong> que las aplicaciones usen las clases <strong>de</strong>l<br />
subsistema en caso necesario necesario.<br />
� Implementación. Factores a tener en cuenta:<br />
�� Reducción <strong>de</strong>l acoplamiento cliente-subsistema. cliente subsistema. Clase<br />
faca<strong>de</strong> abstracta, con clases concretas para las diferentes<br />
implementaciones <strong>de</strong> un subsistema.<br />
�� Clases <strong>de</strong>l subsistema públicas o privadas privadas. Uso <strong>de</strong> espacios<br />
<strong>de</strong> nombres en C++.<br />
65
Faca<strong>de</strong><br />
<strong>Ejemplo</strong>: Una fachada para un sistema <strong>de</strong> compilación<br />
class Scanner {<br />
public:<br />
Scanner(istream&);<br />
virtual ~Scanner();<br />
virtual it lTk Token& &S Scan(); ()<br />
private:<br />
};<br />
istream& _inputStream;<br />
class Parser {<br />
public:<br />
Parser();<br />
virtual ~Parser();<br />
virtual void Parse(Scanner&, ProgramNo<strong>de</strong>Buil<strong>de</strong>r&);<br />
}; }<br />
66
Faca<strong>de</strong><br />
<strong>Ejemplo</strong>: Una fachada para un sistema <strong>de</strong> compilación<br />
class ProgramNo<strong>de</strong>Buil<strong>de</strong>r g {<br />
public:<br />
ProgramNo<strong>de</strong>Buil<strong>de</strong>r();<br />
virtual ProgramNo<strong>de</strong>* NewVariable ( const char* variableName ) const;<br />
virtual ProgramNo<strong>de</strong>* NewAssignment ( ProgramNo<strong>de</strong>* variable variable,<br />
ProgramNo<strong>de</strong>* expression) const;<br />
virtual ProgramNo<strong>de</strong>* NewReturnStatement ( ProgramNo<strong>de</strong>* value ) const;<br />
virtual ProgramNo<strong>de</strong>* g NewCondition ( ProgramNo<strong>de</strong>* g condition,<br />
ProgramNo<strong>de</strong>* truePart,<br />
ProgramNo<strong>de</strong>* falsePart ) const;<br />
// ...<br />
ProgramNo<strong>de</strong>* ProgramNo<strong>de</strong> GetRootNo<strong>de</strong>();<br />
private:<br />
ProgramNo<strong>de</strong>* _no<strong>de</strong>;<br />
};<br />
67
Faca<strong>de</strong><br />
Ej <strong>Ejemplo</strong>: l Una U ffachada h d para un sistema i t <strong>de</strong> d compilación il ió<br />
class ProgramNo<strong>de</strong> {<br />
public:<br />
// program no<strong>de</strong> manipulation<br />
virtual void GetSourcePosition(int& line, int& in<strong>de</strong>x);<br />
// ...<br />
// child manipulation<br />
virtual void Add(ProgramNo<strong>de</strong>*);<br />
virtual void Remove(ProgramNo<strong>de</strong>*);<br />
// ...<br />
virtual void Traverse(Co<strong>de</strong>Generator&);<br />
protected:<br />
ProgramNo<strong>de</strong>();<br />
};<br />
class Co<strong>de</strong>Generator {<br />
public:<br />
virtual void Visit(StatementNo<strong>de</strong>*);<br />
virtual it lvoid idVi Visit(ExpressionNo<strong>de</strong>*);<br />
it(E i N d *)<br />
// ...<br />
protected:<br />
Co<strong>de</strong>Generator(Byteco<strong>de</strong>Stream&);<br />
Co<strong>de</strong>Ge e a o ( y eco<strong>de</strong>S ea &);<br />
protected:<br />
Byteco<strong>de</strong>Stream& _output;<br />
};<br />
68
Faca<strong>de</strong><br />
<strong>Ejemplo</strong>: Una fachada para un sistema <strong>de</strong> compilación<br />
void ExpressionNo<strong>de</strong>::Traverse (Co<strong>de</strong>Generator& cg) {<br />
cg.Visit(this); Vi it(thi )<br />
ListIterator i(_children);<br />
for (i.First(); !i.IsDone(); i.Next()) {<br />
i.CurrentItem()->Traverse(cg);<br />
() ( g);<br />
}<br />
}<br />
class Compiler { // Clase Faca<strong>de</strong><br />
public: bli<br />
Compiler();<br />
virtual void Compile(istream&, Byteco<strong>de</strong>Stream&);<br />
};<br />
void Compiler::Compile ( istream& input, Byteco<strong>de</strong>Stream& output ) {<br />
Scanner scanner(input);<br />
PProgramNo<strong>de</strong>Buil<strong>de</strong>r N d B ild bbuil<strong>de</strong>r; ild<br />
Parser parser;<br />
parser.Parse(scanner, buil<strong>de</strong>r);<br />
RISCCo<strong>de</strong>Generator generator(output);<br />
g ( p );<br />
ProgramNo<strong>de</strong>* parseTree = buil<strong>de</strong>r.GetRootNo<strong>de</strong>();<br />
parseTree->Traverse(generator);<br />
}<br />
69
Proxy<br />
�� Propósito Propósito.<br />
� Proporcionar un representante o substituto <strong>de</strong> otro objeto<br />
para controlar el acceso a este.<br />
� También conocido como.<br />
� Surrogate (substituto).<br />
�� MMotivación. ti ió<br />
� Retrasar el coste <strong>de</strong> creación e inicialización <strong>de</strong> un objeto<br />
hasta que q sea realmente necesario.<br />
� Ej.: al abrir un documento, no abrir las imágenes que no sean<br />
visibles.<br />
aTextDocument:<br />
image<br />
en memoria<br />
anImageProxy:<br />
fileName<br />
data<br />
anImage:<br />
en disco<br />
70
Proxy<br />
�Motivación.<br />
71
Proxy<br />
�� Aplicabilidad<br />
Aplicabilidad.<br />
� Cuando hay necesidad <strong>de</strong> una referencia a un objeto más<br />
flexible o sofisticada que un puntero.<br />
� Proxy Remoto: un representante para un objeto que se<br />
encuentra en otro espacio <strong>de</strong> direcciones.<br />
� Proxy Virtual: Crea objetos costosos por encargo (ej.:<br />
IImageProxy). P )<br />
� Proxy <strong>de</strong> Protección: Controla el acceso al objeto original<br />
(permisos <strong>de</strong> acceso).<br />
� Referencia inteligente: sustituto <strong>de</strong> un puntero, que lleva a<br />
cabo operaciones adicionales cuando se acce<strong>de</strong> a un objeto<br />
(ver ejemplo operadores C++):<br />
� CContar t ell número ú d<strong>de</strong> referencias. f i<br />
� Cargar un objeto persistente en memoria.<br />
� Bloquear el objeto cuando se acce<strong>de</strong> a él (no modificación<br />
concurrente)<br />
concurrente).<br />
� …<br />
72
Proxy<br />
� Estructura.<br />
73
Proxy<br />
� Participantes.<br />
� Proxy.<br />
� Mantiene una referencia que permite al proxy acce<strong>de</strong>r al objeto real.<br />
� Proporciona una interfaz igual que la <strong>de</strong>l sujeto real.<br />
� Controla el acceso al sujeto real, y pue<strong>de</strong> ser responsable <strong>de</strong> crearlo y<br />
borrarlo.<br />
� Otras responsabilida<strong>de</strong>s, <strong>de</strong>pen<strong>de</strong>n <strong>de</strong>l tipo <strong>de</strong> proxy:<br />
• Proxy Remoto: codifican las peticiones peticiones, y se las mandan al sujeto sujeto.<br />
• Proxy virtual: Pue<strong>de</strong> guardar información adicional sobre el sujeto, para<br />
retardar el acceso al mismo.<br />
• Proxy <strong>de</strong> protección: comprueba que el llamador tiene permiso para<br />
realizar la petición petición.<br />
� Subject.<br />
� Define una interfaz común para el RealSubject y el Proxy, <strong>de</strong> tal<br />
manera que el Proxy se pue<strong>de</strong> usan en vez <strong>de</strong>l RealSubject<br />
RealSubject.<br />
� RealSubject.<br />
� Define el objeto real que el proxy representa.<br />
�� Colaboraciones<br />
Colaboraciones.<br />
� El proxy redirige peticiones al sujeto real cuando sea necesario,<br />
<strong>de</strong>pendiendo <strong>de</strong>l tipo <strong>de</strong> proxy.<br />
74
Proxy<br />
�� Consecuencias<br />
Consecuencias.<br />
� Introduce un nivel <strong>de</strong> indirección adicional, que tiene muchos<br />
posibles usos:<br />
�� UUn proxy remoto t pue<strong>de</strong> d ocultar lt el l hhecho h d<strong>de</strong> que un objeto bj t resi<strong>de</strong> id en<br />
otro espacio <strong>de</strong> direcciones.<br />
� Un proxy virtual pue<strong>de</strong> realizar optimizaciones, como crear objetos<br />
bajo <strong>de</strong>manda <strong>de</strong>manda.<br />
� Tanto los proxies <strong>de</strong> protección, como las referencias inteligentes<br />
permiten realizar tareas <strong>de</strong> mantenimiento adicionales cuando se<br />
acce<strong>de</strong> a un objeto objeto.<br />
� Otra optimización: copy-on-write.<br />
� Copiar un objeto gran<strong>de</strong> pue<strong>de</strong> ser costoso.<br />
�� Si la copia no se modifica modifica, no hay necesidad <strong>de</strong> incurrir en dicho<br />
gasto.<br />
� El sujeto mantiene una cuenta <strong>de</strong> referencias, sólo cuando se hace<br />
una operación que modifica el objeto objeto, se copia realmente (ej (ej.: : clase<br />
String <strong>de</strong>l ejemplo <strong>de</strong> operadores C++).<br />
75
Proxy<br />
�� Implementación<br />
Implementación.<br />
� Se pue<strong>de</strong>n explotar las<br />
siguientes características <strong>de</strong><br />
llos llenguajes: j<br />
� Sobrecargar el operador <strong>de</strong><br />
acceso a miembros -> en<br />
C++ C++.<br />
class Image;<br />
extern Image* LoadAnImageFile(const char*);<br />
// external function<br />
class ImagePtr {<br />
public:<br />
ImagePtr(const char* char imageFile);<br />
virtual ~ImagePtr();<br />
virtual Image* operator->();<br />
virtual Image& operator*();<br />
private:<br />
Image* LoadImage();<br />
private:<br />
Image* Image _image; image;<br />
const char* _imageFile;<br />
};<br />
ImagePtr::ImagePtr (const char* theImageFile) {<br />
_imageFile = theImageFile;<br />
_image = 0;<br />
}<br />
Image* Image ImagePtr::LoadImage () {<br />
if (_image == 0) {<br />
_image = LoadAnImageFile(_imageFile);<br />
}<br />
return _image;<br />
}<br />
76
Proxy<br />
Image* Image ImagePtr::operator-> ImagePtr::operator () {<br />
return LoadImage();<br />
}<br />
Image& ImagePtr::operator* () {<br />
return t *LoadImage();<br />
*L dI ()<br />
}<br />
ImagePtr image = ImagePtr("anImageFileName");<br />
image->Draw(Point(50, 100));<br />
// (image.operator->())->Draw(Point(50, 100))<br />
� Sobrecargar “->” no funciona si necesitamos saber a qué operación se<br />
llama: entonces hay que <strong>de</strong>finir dichar operación en el proxy y redirigir la<br />
llamada llamada.<br />
� A veces no hace falta que el proxy conozca el tipo concreto <strong>de</strong>l sujeto<br />
real (si es suficiente con la interfaz <strong>de</strong> la clase abstracta Subject).<br />
77
Proxy<br />
<strong>Ejemplo</strong>: Un Proxy Virtual<br />
class Graphic {<br />
public:<br />
virtual ~Graphic();<br />
virtual void Draw(const Point& at) = 0;<br />
virtual void HandleMouse(Event& event) = 0;<br />
virtual const Point& GetExtent() = 0;<br />
virtual void Load(istream& from) = 0;<br />
virtual void Save(ostream& to) = 0;<br />
protected: p<br />
Graphic();<br />
};<br />
class Image : public Graphic {<br />
public:<br />
Image(const char* file); // loads image from a file<br />
virtual ~Image();<br />
private:<br />
// ...<br />
};<br />
virtual void Draw(const Point& at);<br />
virtual void HandleMouse(Event& event);<br />
virtual const Point& GetExtent();<br />
virtual void Load(istream& from);<br />
virtual void Save(ostream& to);<br />
78
Proxy<br />
<strong>Ejemplo</strong>: Un Proxy Virtual<br />
class ImageProxy : public Graphic { // la clase proxy<br />
public:<br />
ImageProxy(const char* imageFile);<br />
virtual ~ImageProxy();<br />
virtual i t l void id D Draw(const ( t Point& P i t& at); t)<br />
virtual void HandleMouse(Event& event);<br />
virtual const Point& GetExtent();<br />
virtual void Load(istream& from);<br />
virtual void Save(ostream& to);<br />
protected:<br />
Image* GetImage();<br />
private: i t<br />
};<br />
Image* _image;<br />
Point _extent;<br />
char* c a _fileName; e a e;<br />
79
Proxy<br />
<strong>Ejemplo</strong>: Un Proxy Virtual<br />
ImageProxy::ImageProxy (const char char* fileName) {<br />
_fileName = strdup(fileName);<br />
_extent = Point::Zero; // don't know extent yet<br />
_image = 0;<br />
}<br />
Image* ImageProxy::GetImage() {<br />
if (_image == 0) {<br />
_image = new Image(_fileName);<br />
}<br />
return _image;<br />
}<br />
void ImageProxy::Save (ostream& to) {<br />
to _extent >> _fileName;<br />
}<br />
const Point& ImageProxy::GetExtent () {<br />
if (_extent ( t t == Point::Zero) P i t Z ) {<br />
_extent = GetImage()->GetExtent();<br />
}<br />
return _extent;<br />
}<br />
void ImageProxy::Draw (const Point& at) {<br />
GetImage()->Draw(at);<br />
}<br />
void ImageProxy::HandleMouse (Event& event) {<br />
GetImage()->HandleMouse(event);<br />
}<br />
80
Proxy<br />
<strong>Ejemplo</strong>: Un Proxy Virtual<br />
class TextDocument {<br />
public:<br />
TextDocument();<br />
void Insert(Graphic*);<br />
// ...<br />
};<br />
TextDocument* text = new TextDocument;<br />
// ...<br />
text->Insert(new ImageProxy("anImageFileName"));<br />
81
Ejercicio (Junio <strong>de</strong> 208)<br />
�� SSea lla aplicación li ió d<strong>de</strong> pedidos did vista i t en ttemas anteriores:<br />
t i
Ejercicio<br />
� En el contexto <strong>de</strong> la aplicación anterior, supón<br />
que sólo se pue<strong>de</strong> acce<strong>de</strong>r al disponible <strong>de</strong> una<br />
cuenta <strong>de</strong> pago si se ha introducido una clave.<br />
Utilizando patrones <strong>de</strong> diseño, implementa en<br />
C++ un Proxy <strong>de</strong> Protección que asegure que se<br />
acce<strong>de</strong> al disponible <strong>de</strong> la cuenta sólo si la clave<br />
es correcta (supón que la clave se pi<strong>de</strong> por la<br />
consola). La clave se almacena en el proxy, y<br />
éste recuerda si ya se ha introducido<br />
correctamente o no.
#inclu<strong>de</strong> "stdafx.h"<br />
#inclu<strong>de</strong> <br />
#inclu<strong>de</strong> <br />
using std::cout;<br />
using std::string;<br />
using std::cin;<br />
class Cuenta<br />
{<br />
public:<br />
virtual int obtenerDisponible () = 0;<br />
};<br />
class CuentaReal : public Cuenta<br />
{<br />
private:<br />
public:<br />
int disponible;<br />
CuentaReal (int d ) : disponible (d) {}<br />
int obtenerDisponible() {return disponible; }<br />
Solución (1)<br />
};<br />
class ProxyCuenta: public Cuenta<br />
{<br />
private:<br />
CuentaReal * cuenta;<br />
string clave;<br />
bool correcta;<br />
bool intro;<br />
public:<br />
ProxyCuenta ( string psswd, psswd CuentaReal & c ) :<br />
clave(psswd), cuenta(&c), intro(false), correcta(false) {}<br />
int obtenerDisponible();<br />
};
int ProxyCuenta::obtenerDisponible() {<br />
if (correcta) return cuenta->obtenerDisponible();<br />
else if (!intro) {<br />
intro = true;<br />
string cl;<br />
cout > cl;<br />
if (cl == clave) {<br />
correcta = true;<br />
return cuenta->obtenerDisponible();<br />
}<br />
else {<br />
correcta = false;<br />
cout
Adapter<br />
� Propósito.<br />
� Convierte el interfaz <strong>de</strong> una clase en otro que q espera p el cliente.<br />
� El adapter permite trabajar juntas a clases que <strong>de</strong> otra forma no podrían por<br />
tener interfaces incompatibles.<br />
� También conocido como.<br />
� Wrapper (envoltorio).<br />
� Motivación.<br />
�� A veces una clase <strong>de</strong> una biblioteca que ha sido diseñada para reutilizarse reutilizarse,<br />
no pue<strong>de</strong> hacerlo porque su interfaz no coinci<strong>de</strong> con la interfaz específica<br />
<strong>de</strong> dominio que requiere la aplicación.<br />
�� Ej Ej.: : un editor <strong>de</strong> dibujo dibujo. Objetos gráficos gráficos, con una clase base abstracta<br />
Shape.<br />
� Queremos reutilizar una clase existente TextView para implementar TextShape<br />
(quizá no tengamos el código fuente <strong>de</strong> TextView).<br />
� Solución: Definir una clase TextShape que adapte el interfaz <strong>de</strong> TextView a<br />
Shape.<br />
� Se pue<strong>de</strong> hacer <strong>de</strong> dos maneras:<br />
• Adaptador <strong>de</strong> clase: Heredando el interfaz <strong>de</strong> Shape y la implementación <strong>de</strong><br />
TextView.<br />
• Adaptador <strong>de</strong> objeto: Componiendo un objeto TextView <strong>de</strong>ntro <strong>de</strong> un TextShape, 86e<br />
implementando TextShape en términos <strong>de</strong> la interfaz <strong>de</strong> TextView.
Adapter<br />
�Motivación.<br />
� Adaptador p <strong>de</strong> objeto. j<br />
87
Adapter<br />
�Estructura.<br />
�Adaptador p <strong>de</strong> clase.<br />
88
Adapter<br />
�Estructura.<br />
�Adaptador p <strong>de</strong> objeto. j<br />
89
Indice<br />
� Introducción.<br />
� <strong>Patrones</strong> <strong>de</strong> Creación.<br />
� <strong>Patrones</strong> Estructurales.<br />
�<strong>Patrones</strong> �<strong>Patrones</strong> <strong>de</strong> Comportamiento<br />
Comportamiento.<br />
�Iterator.<br />
�Observer.<br />
�Template Method.<br />
�State.<br />
�Strategy. gy<br />
�Command.<br />
�Chain �Chain of Responsibility.<br />
Responsibility<br />
� Conclusiones.<br />
� Bibliografía.<br />
90
<strong>Patrones</strong> <strong>de</strong> Comportamiento<br />
�Tratan sobre algoritmos y la asignación <strong>de</strong><br />
responsabilida<strong>de</strong>s p entre objetos. j<br />
�Describen no sólo patrones <strong>de</strong> clases y<br />
objetos objetos, sino patrones <strong>de</strong> comunicación<br />
entre ellos.<br />
�Caracterizan un flujo <strong>de</strong> control complejo,<br />
difícil <strong>de</strong> seguir en tiempo <strong>de</strong> ejecución.<br />
�Permiten que el diseñador se concentre<br />
sólo ól en cómo ó iinterconectar t t objetos.<br />
bj t
Iterator<br />
�� Propósito Propósito.<br />
� Proporciona un medio <strong>de</strong> acce<strong>de</strong>r a los elementos <strong>de</strong> un<br />
contenedor secuencialmente sin exponer su representación<br />
interna interna.<br />
� También Conocido Como.<br />
� Cursor.<br />
� Motivación.<br />
� Un contenedor (p.ej.: una lista) <strong>de</strong>be proporcionar un medio <strong>de</strong><br />
navegar g sus datos secuencialmente sin exponer p su<br />
representación interna.<br />
� Se <strong>de</strong>be po<strong>de</strong>r atravesar la lista <strong>de</strong> varias maneras,<br />
<strong>de</strong>pendiendo <strong>de</strong> lo que se quiera hacer.<br />
� Probablemente no interesa añadir a la lista operaciones para<br />
realizar los diferentes recorridos.<br />
� Pue<strong>de</strong> necesitarse hacer más <strong>de</strong> un recorrido simultáneamente.<br />
� Dar la responsabilidad <strong>de</strong> acce<strong>de</strong>r y recorrer el objeto lista a un<br />
objeto Iterator.<br />
92
Iterator<br />
� Motivación.<br />
list<br />
List<br />
+ Count()<br />
+ Append(Element)<br />
+ Remove(Element)<br />
1 *<br />
ListIterator<br />
- in<strong>de</strong>x<br />
+ First()<br />
+Next() + Next()<br />
+ IsDone()<br />
+ CurrentItem()<br />
� Antes <strong>de</strong> instanciar el ListIterator, se ha <strong>de</strong> proporcionar la lista.<br />
� Una vez que se tiene la instancia, se pue<strong>de</strong> acce<strong>de</strong>r a los<br />
elementos <strong>de</strong> la lista secuencialmente<br />
secuencialmente.<br />
� Separar el mecanismo <strong>de</strong> recorrido <strong>de</strong>l objeto lista, nos permite<br />
<strong>de</strong>finir iteradores que implementen distintas estrategias.<br />
93
Iterator<br />
� Motivación.<br />
� El iterador y la lista están acoplados: el cliente sabe que lo que se está recorriendo es una lista.<br />
� Es mejor po<strong>de</strong>r cambiar el contenedor sin tener que cambiar el código cliente: iteración<br />
polimórfica.<br />
skiplist<br />
1<br />
AbstractList<br />
+CreateIterator()<br />
+ Count()<br />
+ AAppend(Element) d(El t)<br />
+ Remove(Element)<br />
…<br />
Cli Client t<br />
1 list<br />
*<br />
Iterator<br />
+ First()<br />
+ Next()<br />
+ IsDone()<br />
+ CurrentItem()<br />
SkipList List<br />
ListIterator SkipListIterator<br />
� Po<strong>de</strong>mos hacer responsables a las listas <strong>de</strong> crear sus propios iteradores, mediante un factory<br />
method (CreateIterator).<br />
� Se pue<strong>de</strong> <strong>de</strong>finir algoritmos generales que usan un iterador genérico (en C++: “for_each”, “find_if”, 94<br />
“count”, etc)<br />
*
Iterator<br />
� Aplicabilidad. Usar el patrón :<br />
�� para acce<strong>de</strong>r al contenido <strong>de</strong> un contenedor sin exponer su<br />
representación interna.<br />
� para permitir varios recorridos sobre contenedores.<br />
� para proporcionar una interfaz uniforme para recorres distintos tipos<br />
<strong>de</strong> contenedores (esto es, permitir la iteración polimórfica).<br />
� Estructura. Iterator<br />
Aggregate<br />
+CreateIterator ()<br />
ConcreteAggregate<br />
+CreateIterator ()<br />
return new ConcreteIterator (this)<br />
Client<br />
+First ()<br />
+Next ()<br />
+IsDone IsDone ()<br />
+CurrentItem ()<br />
ConcreteIterator<br />
95
Iterator<br />
�� Participantes<br />
Participantes.<br />
� Iterator.<br />
� Define una interfaz para recorrer los elementos y acce<strong>de</strong>r a ellos.<br />
� ConcreteIterator.<br />
� Implementa la interfaz Iterator.<br />
� Mantiene la posición actual en el recorrido <strong>de</strong>l agregado.<br />
� Aggregate.<br />
� Define una interfaz para crear un objeto Iterator.<br />
� ConcreteAggregate.<br />
� Implementa una interfaz <strong>de</strong> creación <strong>de</strong>l Iterator para <strong>de</strong>volver una<br />
instancia <strong>de</strong>l ConcreteIterator apropiado.<br />
� Colaboraciones.<br />
� Un ConcreteIterator sabe cuál es el objeto actual <strong>de</strong>l agregado y<br />
pue<strong>de</strong> calcular el objeto siguiente <strong>de</strong>l recorrido.<br />
96
Iterator<br />
�� Consecuencias<br />
Consecuencias.<br />
� Permite variaciones en el recorrido <strong>de</strong> un agregado.<br />
� Los iteradores simplifican la interfaz <strong>de</strong>l contenedor.<br />
� Se pue<strong>de</strong> hacer más <strong>de</strong> un recorrido a la vez sobre un<br />
agregado.<br />
�� Implementación.<br />
� ¿Quién controla la iteración?.<br />
� El cliente controla la iteración: iterador externo.<br />
�� El iterador controla la iteración: iterador interno. interno<br />
� ¿Quién <strong>de</strong>fine el algoritmo <strong>de</strong> recorrido?<br />
� El iterador.<br />
�� El agregado, d y el l it iterador d sólo ól almacena l el l estado t d d<strong>de</strong> lla<br />
iteración. A este tipo <strong>de</strong> iterador se le llama cursor.<br />
� ¿Cómo <strong>de</strong> robusto es el iterador?<br />
�� Iterador robusto: Las inserciones y borrados no interfieren en el<br />
recorrido (y se hace sin copiar el agregado).<br />
97
Iterator<br />
�� IImplementación. l t ió<br />
� Operaciones adicionales <strong>de</strong>l iterador.<br />
�� Por ejemplo, iteradores or<strong>de</strong>nados podrían tener una operación<br />
Previous. Otras como SkipTo.<br />
� Usar iteradores polimórficos en C++.<br />
�� Los iteradores polimórficos han <strong>de</strong> crearse dinámicamente por un<br />
método <strong>de</strong> fabricación.<br />
� El cliente a<strong>de</strong>más es responsable <strong>de</strong> borrarlos (propenso a<br />
errores) errores).<br />
� Iteradores para Composites.<br />
� Los iteradores externos pue<strong>de</strong>n ser complicados <strong>de</strong> implementar<br />
en estructuras t t recursivas. i<br />
� NullIterators.<br />
� Es un iterador <strong>de</strong>generado g qque ayuda y a manejar j condiciones<br />
límite.<br />
98
Iterator<br />
<strong>Ejemplo</strong><br />
11. Interfaces <strong>de</strong> la lista y el iterador iterador.<br />
template <br />
class List {<br />
public:<br />
List(long size = DEFAULT_LIST_CAPACITY);<br />
long Count() const;<br />
Item& Get(long in<strong>de</strong>x) const;<br />
// ...<br />
};<br />
template <br />
class Iterator {<br />
public:<br />
virtual void First() = 0;<br />
virtual void Next() = 0;<br />
virtual bool IsDone() const = 0;<br />
virtual Item CurrentItem() const = 0;<br />
protected:<br />
Iterator();<br />
};<br />
99
Iterator<br />
<strong>Ejemplo</strong><br />
22. Implementaciones <strong>de</strong> las subclases <strong>de</strong>l iterador iterador.<br />
template <br />
class ListIterator : public Iterator {<br />
public:<br />
ListIterator(const List* aList) _list(aList), _current(0) {}<br />
virtual void First() {_current = 0;}<br />
virtual void Next() {_current++;}<br />
virtual bool IsDone() const {return _current >= _list->Count(); }<br />
virtual Item CurrentItem() const;<br />
private:<br />
const List* List _list; list;<br />
long _current;<br />
};<br />
template <br />
Item ListIterator::CurrentItem () const {<br />
if (IsDone()) throw IteratorOutOfBounds;<br />
return _list->Get(_current);<br />
}<br />
// Se pue<strong>de</strong> implementar un ReverseListIterator, con First<br />
// posicionando el iterador al final <strong>de</strong> la lista, y Next <strong>de</strong>crementando<br />
100
Iterator<br />
<strong>Ejemplo</strong><br />
33. UUso d<strong>de</strong>l l iiterador. d<br />
void PrintEmployees (Iterator& i) {<br />
for (i.First(); ( (); !i.IsDone(); (); i.Next()) ()) {<br />
i.CurrentItem()->Print();<br />
}<br />
}<br />
List* employees;<br />
// ...<br />
ListIterator forward(employees);<br />
ReverseListIterator backward(employees);<br />
PrintEmployees(forward);<br />
PrintEmployees(backward);<br />
101
Iterator<br />
<strong>Ejemplo</strong><br />
4. Evitar ajustarse j a una implementación p<br />
concreta <strong>de</strong> la lista.<br />
� Supongamos que tenemos SkipList y SkipListIterator.<br />
� Se pue<strong>de</strong> introducir un AbstractList para estandarizar la interfaz <strong>de</strong> la lista<br />
(List ( y SkipList p son subclases <strong>de</strong> AbstractList). )<br />
� Para permitir iteración polimórfica, AbstractList <strong>de</strong>fine un factory method<br />
CreateIterator.<br />
template <br />
class AbstractList {<br />
public:<br />
virtual Iterator* CreateIterator() const = 0;<br />
// ...<br />
};<br />
template <br />
Iterator* List::CreateIterator () const {<br />
return new ListIterator(this);<br />
}<br />
// we know only y that we have an AbstractList<br />
AbstractList* employees;<br />
// ...<br />
Iterator* iterator = employees->CreateIterator();<br />
Pi PrintEmployees(*iterator);<br />
tE l (*it t )<br />
<strong>de</strong>lete iterator;<br />
102
Iterator<br />
<strong>Ejemplo</strong><br />
5. Asegurarse g <strong>de</strong> que q los iteradores se borran.<br />
� Crear un IteratorPtr, que actua <strong>de</strong> Proxy para un Iterator.<br />
� Se ocupa <strong>de</strong> borrar el Iterator cuando se sale <strong>de</strong> ámbito.<br />
template <br />
class IteratorPtr {<br />
public:<br />
IteratorPtr(Iterator* i): _i(i) i(i) { }<br />
~IteratorPtr() { <strong>de</strong>lete _i; }<br />
Iterator* operator->() { return _i; }<br />
Iterator& operator*() p () { return *_i; _ }<br />
private:<br />
// disallow copy and assignment to avoid<br />
// multiple <strong>de</strong>letions of _i:<br />
IteratorPtr(const IteratorPtr&);<br />
IteratorPtr& operator=(const IteratorPtr&);<br />
private:<br />
Iterator* _i; _<br />
};<br />
AbstractList* employees;<br />
// ...<br />
IIteratorPtr P E l *<br />
iterator(employees->CreateIterator());<br />
PrintEmployees(*iterator);<br />
103
Iterator<br />
<strong>Ejemplo</strong><br />
6. Un iterador interno.<br />
� El iterador controla la iteración, y aplica una operación a cada elemento.<br />
� La operación se pue<strong>de</strong> configurar:<br />
template <br />
class ListTraverser {<br />
public:<br />
�� Pasando un puntero a una función función, o a un objeto función función.<br />
� Mediante subclasificación.<br />
ListTraverser(List* aList):_iterator(aList) { };<br />
bool Traverse();<br />
protected:<br />
virtual bool ProcessItem(const Item&) = 0;<br />
private:<br />
ListIterator _iterator;<br />
};<br />
template <br />
bool ListTraverser::Traverse () {<br />
bool result = false;<br />
for ( _iterator.First(); iterator First(); ! !_iterator.IsDone();_iterator.Next()) iterator IsDone(); iterator Next()) {<br />
result = ProcessItem(_iterator.CurrentItem());<br />
if (result == false) break;<br />
}<br />
return result;<br />
}<br />
104
Iterator<br />
<strong>Ejemplo</strong><br />
66. UUn iiterador d iinterno<br />
� Imprimir los n primeros empleados <strong>de</strong> una lista.<br />
class PrintNEmployees : public ListTraverser {<br />
public:<br />
PrintNEmployees(List* aList, int n) :<br />
ListTraverser(aList),<br />
p y ( )<br />
_total(n), _count(0) { }<br />
protected:<br />
bool ProcessItem(Employee* const&);<br />
private:<br />
}; }<br />
int _total;<br />
int _count;<br />
bool PrintNEmployees::ProcessItem (Employee* const& e) {<br />
_count++;<br />
e e->Print(); >Print();<br />
return _count < _total;<br />
}<br />
105
Iterator<br />
<strong>Ejemplo</strong><br />
66. UUn it iterador d iinterno t<br />
� Imprimir los n primeros empleados <strong>de</strong> una lista.<br />
List* List Employee employees;<br />
// ...<br />
PrintNEmployees pa(employees, 10);<br />
pa.Traverse();<br />
� Comparación con un iterador externo:<br />
ListIterator i(employees);<br />
int count = 0;<br />
for (i.First(); !i.IsDone(); i.Next()) {<br />
count++;<br />
i.CurrentItem()->Print();<br />
if (count >= 10) break;<br />
}<br />
106
Iterator<br />
<strong>Ejemplo</strong><br />
66. UUn iiterador d iinterno<br />
� Pue<strong>de</strong>n encapsular distintos tipos <strong>de</strong> operaciones.<br />
template <br />
class FilteringListTraverser {<br />
public:<br />
FilteringListTraverser(List* aList);<br />
bool Traverse(); ()<br />
protected:<br />
virtual bool ProcessItem(const Item&) = 0;<br />
virtual bool TestItem(const ( Item&) ) = 0;<br />
private:<br />
ListIterator _iterator;<br />
};<br />
template <br />
void FilteringListTraverser::Traverse () {<br />
bool result = false;<br />
for (_iterator.First();!_iterator.IsDone();_iterator.Next()) (_ () _ () _ ()) {<br />
if (TestItem(_iterator.CurrentItem())) {<br />
result = ProcessItem(_iterator.CurrentItem());<br />
if (result == false) break;<br />
}<br />
}<br />
return result;<br />
}<br />
107
Observer<br />
�� PPropósito. ó it<br />
� Define una <strong>de</strong>pen<strong>de</strong>ncia <strong>de</strong> uno-a-muchos entre objetos, <strong>de</strong><br />
forma que q cuando un objeto j cambie <strong>de</strong> estado se notifique q y<br />
actualicen automáticamente todos los objetos que <strong>de</strong>pen<strong>de</strong>n<br />
<strong>de</strong> él.<br />
�� También conocido como. como<br />
� Depen<strong>de</strong>nts, Publish-Subscribe<br />
� Motivación.<br />
� Mantener consistencia entre objetos relacionados.<br />
� No queremos obtener dicha consistencia aumentando el<br />
acoplamiento entre clases. clases<br />
� Ej.: separación <strong>de</strong> la presentación en GUI <strong>de</strong> los datos <strong>de</strong><br />
aplicación subyacente.<br />
108
Observer<br />
� Motivación.<br />
C<br />
D<br />
B<br />
A<br />
A B C D<br />
X 60 20 15 5<br />
Y 40 25 15 20<br />
Z 10 10 20 60<br />
Mo<strong>de</strong>lo<br />
A: 40%<br />
B: 25%<br />
CC: 15%<br />
D: 20%<br />
40<br />
30<br />
20<br />
10<br />
0<br />
A B C D<br />
109
Observer<br />
� Aplicabilidad.<br />
� Cuando una abstracción tiene dos aspectos y uno <strong>de</strong>pen<strong>de</strong> <strong>de</strong>l otro.<br />
� Cuando un cambio en un objeto requiere cambiar otros, y no sabemos<br />
cuántos hay yqque<br />
cambiar.<br />
� Cuando un objeto <strong>de</strong>bería ser capaz <strong>de</strong> notificar a otros sin hacer<br />
suposiciones sobre quiénes son dichos objetos (esto es, no queremos<br />
que los objetos estén fuertemente acoplados).<br />
acoplados)<br />
� Estructura.<br />
observers<br />
Subject Observer<br />
00..1 1<br />
1 1..* *<br />
+Attach (Observer)<br />
+Detach (Observer)<br />
+Notify ()<br />
ConcreteSubject<br />
- subjectState<br />
+GetState ()<br />
+SetState ()<br />
0..1<br />
forall o in observers<br />
o.Update()<br />
subject<br />
+Update()<br />
ConcreteObserver<br />
- observerState<br />
+Update ()<br />
return subjectState observerState=<br />
subject->GetState()<br />
110
Observer<br />
� Participantes.<br />
�� SSubject. bj t<br />
� Conoce a sus observadores, que pue<strong>de</strong>n ser un número arbitrario.<br />
� Proporciona un interfaz para añadir y quitar objetos Observer.<br />
�� Ob Observer.<br />
� Define un interfaz <strong>de</strong> actualización para los objetos que <strong>de</strong>ben ser<br />
notificados sobre cambios en un sujeto.<br />
�� ConcreteSubject<br />
ConcreteSubject.<br />
� Almacena estado <strong>de</strong> interés para ConcreteObservers.<br />
� Manda notificaciones a sus observadores cuando su estado cambia.<br />
�� ConcreteObserver<br />
ConcreteObserver.<br />
� Mantiene una referencia a objetos ConcreteSubject.<br />
� Almacena el estado que <strong>de</strong>be ser consistente con el <strong>de</strong>l sujeto.<br />
�� Implementa el interfaz <strong>de</strong> actualización <strong>de</strong>l Observer para mantener su<br />
estado consistente con el <strong>de</strong>l sujeto.<br />
111
Observer<br />
� Colaboraciones.<br />
� El ConcreteSubject notifica a sus observadores cada vez que se<br />
produce un cambio que pudiera hacer que el estado <strong>de</strong> estos fuese<br />
inconsistente con el suyo. y<br />
� Después <strong>de</strong> ser notificado <strong>de</strong>l cambio, un ConcreteObserver pue<strong>de</strong><br />
pedir al subject más información.<br />
SetState()<br />
:ConcreteSubject<br />
Notify()<br />
Update()<br />
GetState()<br />
Update()<br />
GetState()<br />
barDiagram<br />
:ConcreteObserver<br />
sectorDiagram<br />
:ConcreteObserver<br />
112
Observer<br />
�� Consecuencias<br />
Consecuencias.<br />
� Permite modificar los sujetos y observadores <strong>de</strong> manera<br />
in<strong>de</strong>pendiente.<br />
�� SSe pue<strong>de</strong>n d reutilizar tili llos sujetos j t sin i sus observadores b d y<br />
viceversa.<br />
� Se pue<strong>de</strong>n añadir observadores sin modificar el sujeto u otros<br />
observadores<br />
observadores.<br />
� Acoplamiento abstracto entre sujeto y observador. El sujeto no<br />
conoce la clase concreta <strong>de</strong> ningún observador (el acoplamiento<br />
es mínimo) mínimo).<br />
� Capacidad <strong>de</strong> comunicación mediante difusión. La notificación<br />
<strong>de</strong>l sujeto se envía automáticamente a todos los observadores<br />
suscritos. Se pue<strong>de</strong>n p añadir y quitar q observadores en cualquier q<br />
momento.<br />
� Actualizaciones inesperadas. Una operación aparentemente<br />
inofensiva sobre el sujeto pue<strong>de</strong> <strong>de</strong>senca<strong>de</strong>nar una cascada <strong>de</strong><br />
cambios bi en llos observadores.<br />
b d<br />
113
Observer<br />
�� Implementación<br />
Implementación.<br />
� Correspon<strong>de</strong>ncia entre sujetos y observadores.<br />
� Que el sujeto guar<strong>de</strong> referencias a los observadores a los que <strong>de</strong>be<br />
notificar notificar.<br />
� Observar más <strong>de</strong> un sujeto.<br />
� Ej.: una hoja <strong>de</strong> cálculo pue<strong>de</strong> observar más <strong>de</strong> un origen <strong>de</strong> datos.<br />
�� Exten<strong>de</strong>r la interfaz <strong>de</strong> actualización para que el observador sepa<br />
qué sujeto se ha actualizado (quizá simplemente el sujeto se pase<br />
a sí mismo como parámetro <strong>de</strong>l update()).<br />
� ¿Quién ¿Q dispara p la actualización?<br />
� Las operaciones que cambien el estado <strong>de</strong>l sujeto llaman a Notify().<br />
• Ventaja: los clientes no tienen que hacer nada.<br />
• Inconveniente: no es óptimo si hay varios cambios <strong>de</strong> estado seguidos.<br />
� Los clientes llaman a Notify():<br />
• Ventaja: se pue<strong>de</strong> optimizar llamando a notify sólo <strong>de</strong>spués <strong>de</strong> varios<br />
cambios.<br />
• Inconveniente: los clientes tienen la responsabilidad añadida <strong>de</strong> llamar<br />
a Notify().<br />
114
Observer<br />
� Implementación.<br />
�Referencias perdidas a sujetos borrados.<br />
� Una manera <strong>de</strong> evitarlo es notificar a los observadores<br />
cuando se borra un sujeto.<br />
�Asegurarse �Asegurarse <strong>de</strong> que el estado <strong>de</strong>l Sujeto sea consistente<br />
consigo mismo antes <strong>de</strong> la notificación:<br />
� Hay que tener cuidado con las operaciones heredadas.<br />
void MySubject::Operation (int newValue) {<br />
BaseClassSubject::Operation(newValue);<br />
// trigger notification<br />
_myInstVar += newValue;<br />
// update subclass state (too late!)<br />
}<br />
115
Observer<br />
�� Implementación<br />
Implementación.<br />
� Evitar protocolos específicos <strong>de</strong>l obervador: los mo<strong>de</strong>los<br />
push y pull.<br />
� Las implementaciones <strong>de</strong> observer suelen hacer que el sujeto<br />
envie información adicional como parámetro <strong>de</strong> Update().<br />
� Dos extremos:<br />
• Mo<strong>de</strong>lo Push: el sujeto envía información <strong>de</strong>talla <strong>de</strong>l cambio cambio, quieran<br />
los observadores o no.<br />
Inconveniente: observadores menos reutilizables.<br />
• Mo<strong>de</strong>lo Pull: el sujeto no envía nada, y los observadores pi<strong>de</strong>n<br />
d<strong>de</strong>spués é llos d<strong>de</strong>talles t ll explícitamente.<br />
lí it t<br />
Inconveniente: pue<strong>de</strong> ser poco eficiente.<br />
� Especificar las modificaciones <strong>de</strong> interés explícitamente:<br />
�� Mejorar la eficiencia haciendo que los observadores registren<br />
solo aquellos eventos que les interesen.<br />
� Los observadores se subscriben a aspectos <strong>de</strong>l sujeto.<br />
116
Observer<br />
� Implementación.<br />
�� Encapsular la semántica <strong>de</strong> las operaciones complejas complejas.<br />
Subject<br />
+Attach (Observer o)<br />
+Detach (Observer)<br />
+Notify ()<br />
chman->Notify()<br />
chman >Notify()<br />
� Si la relación <strong>de</strong> <strong>de</strong>pen<strong>de</strong>ncia entre sujetos y observadores es compleja, pue<strong>de</strong> ser<br />
necesario un objeto intermedio para la gestión <strong>de</strong> cambios (ChangeManager).<br />
� Minimizar el trabajo j necesario ppara qque los observadores reflejen j los cambios en el<br />
sujeto.<br />
� Ej.: si varios sujetos han <strong>de</strong> cambiarse, asegurarse <strong>de</strong> que se notifique a los<br />
observadores sólo <strong>de</strong>spués <strong>de</strong>l cambio en el último sujeto.<br />
chman->Registar(this,o)<br />
forall s in subjects:<br />
forall o in observers:<br />
o->Update(s)<br />
subjects<br />
0..*<br />
chman<br />
1<br />
ChangeManager<br />
Subject-Observer mapping<br />
+Register (Subject,Observer)<br />
+Unregister (Subject,Observer)<br />
+Notify ()<br />
observers<br />
1..*<br />
SimpleChangeManager DAGChangeManager<br />
+Register (Subject,Observer)<br />
+Unregister (Subject,Observer)<br />
+Notify ()<br />
+Register (Subject,Observer)<br />
+Unregister (Subject,Observer)<br />
+Notify ()<br />
Observer<br />
+Update(Subject)<br />
Marcar todos los observers<br />
a actualizar.<br />
Actualizar los observers<br />
marcados.<br />
117
Observer<br />
<strong>Ejemplo</strong><br />
class Subject;<br />
class Observer {<br />
public:<br />
virtual ~ Observer(); ()<br />
virtual void Update (Subject*<br />
theChangedSubject) = 0;<br />
// soporte <strong>de</strong> múltiples subjects<br />
protected:<br />
Observer();<br />
};<br />
class Subject {<br />
public:<br />
virtual ~Subject(); j ()<br />
virtual void Attach(Observer*);<br />
virtual void Detach(Observer*);<br />
virtual void Notify();<br />
protected:<br />
Subject();<br />
private:<br />
List *_observers;<br />
_<br />
};<br />
void Subject::Attach (Observer* o) {<br />
_observers->Append(o);<br />
}<br />
void Subject::Detach (Observer* o) {<br />
_observers->Remove(o);<br />
}<br />
void Subject::Notify () {<br />
ListIterator i(_observers);<br />
for (i.First(); !i.IsDone(); i.Next()) {<br />
ii.CurrentItem()->Update(this); CurrentItem() >Update(this);<br />
}<br />
118<br />
}
Observer<br />
<strong>Ejemplo</strong><br />
class ClockTimer : public Subject { class DigitalClock: public Widget, public<br />
// Concrete subject<br />
Observer {<br />
public:<br />
public:<br />
ClockTimer(); ()<br />
DigitalClock(ClockTimer*);<br />
virtual int GetHour();<br />
virtual it l~DigitalClock(); DiitlClk() virtual int GetMinute();<br />
virtual void Update(Subject*);<br />
virtual int GetSecond();<br />
// overri<strong>de</strong>s Observer operation<br />
void Tick();<br />
virtual void Draw();<br />
};<br />
// overri<strong>de</strong>s Widget operation;<br />
// <strong>de</strong>fines how to draw the digital clock<br />
void ClockTimer::Tick () {<br />
private:<br />
// update internal time-keeping state<br />
Cl ClockTimer* kTi * _subject; bj t<br />
// ...<br />
};<br />
Notify();<br />
DigitalClock::DigitalClock (ClockTimer* s) {<br />
} _subject bj t = s;<br />
_subject->Attach(this);<br />
}<br />
DigitalClock::~DigitalClock DigitalClock:: DigitalClock () {<br />
_subject->Detach(this);<br />
}<br />
119
Observer<br />
<strong>Ejemplo</strong><br />
void DigitalClock::Update (Subject* theChangedSubject) {<br />
if (theChangedSubject == _subject) Draw();<br />
}<br />
void DigitalClock::Draw () {<br />
int hour = _subject->GetHour(); // get the new values from the subject<br />
}<br />
int minute = _subject->GetMinute();<br />
// etc.<br />
// draw the digital clock<br />
class AnalogClock : public Widget Widget, public Observer {<br />
public:<br />
AnalogClock(ClockTimer*);<br />
virtual void Update(Subject*);<br />
virtual void Draw();<br />
// ...<br />
};<br />
ClockTimer* timer = new ClockTimer;<br />
AnalogClock* analogClock = new AnalogClock(timer);<br />
DigitalClock* digitalClock = new DigitalClock(timer);<br />
120
Observer<br />
Usos Conocidos<br />
�� Sistemas <strong>de</strong> <strong>de</strong> eventos en Java (observer=listener)<br />
(observer listener)<br />
� AWT/Swing<br />
� Javabeans<br />
� MVC en el sistema <strong>de</strong> ventanas <strong>de</strong> Smalltalk<br />
� Mo<strong>de</strong>l=Subject<br />
�� View=Observer<br />
� Controller=Cualquier objeto que cambie el estado <strong>de</strong> Subject<br />
� MVC en entornos web (J2EE)<br />
� Mo<strong>de</strong>l=EJB<br />
� View=JSP<br />
�� Controller=servlet<br />
Controller servlet<br />
121
Template Method<br />
� Propósito. p<br />
� Definir el esqueleto <strong>de</strong> un algoritmo, <strong>de</strong>legando en las subclases<br />
alguno <strong>de</strong> sus pasos.<br />
�� Permite que las subclases cambien pasos <strong>de</strong> un algoritmo sin cambiar<br />
su estructura.<br />
� Motivación.<br />
� Ej.: MFCs, abrir un fichero.<br />
Document<br />
docs<br />
Application pp<br />
1 1..* *<br />
+Abrir()<br />
+Cerrar()<br />
+Guardar()<br />
+DoRead() D R d()<br />
MyDocument<br />
y<br />
+DoRead()<br />
return MyDocument<br />
+AddDocument()<br />
+OpenDocument()<br />
+DoCreateDocument()<br />
+CanOpenDocument()<br />
+AboutToOpenDocument()<br />
MyApplication<br />
+DoCreateDocument()<br />
+CanOpenDocument()<br />
+AboutToOpenDocument()<br />
void Application::OpenDocument (const char* name) {<br />
if (!CanOpenDocument(name)) {<br />
// cannot handle this document<br />
return;<br />
}<br />
Document* doc = DoCreateDocument();<br />
if (doc) {<br />
_docs->AddDocument(doc);<br />
AboutToOpenDocument(doc);<br />
doc->Open();<br />
doc doc->DoRead();<br />
>DoRead();<br />
}<br />
122<br />
}
Template Method<br />
� Aplicabilidad.<br />
� Para implementar las partes <strong>de</strong> un algoritmo que no cambian,<br />
y <strong>de</strong>jar que las subclases implementen el comportamiento<br />
que pue<strong>de</strong> variar variar.<br />
� Cuando el comportamiento repetido <strong>de</strong> varias subclases<br />
<strong>de</strong>bería factorizarse y localizarse en una clase común, para<br />
evitar código duplicado.<br />
� Para controlar las extensiones <strong>de</strong> las subclases.<br />
�� EEstructura. t t<br />
ClaseAbstracta<br />
+TemplateMethod()<br />
+PrimitiveOperation1() …<br />
+PrimitiveOperation2()<br />
PrimitiveOperation1()<br />
+…<br />
…<br />
PrimitiveOperation2()<br />
ConcreteClass<br />
+PrimitiveOperation1()<br />
+PrimitiveOperation2()<br />
123
State<br />
� Propósito.<br />
�� Permitir que un objeto modifique su comportamiento cada vez que cambie su<br />
estado interno.<br />
� Parecerá que cambia la clase <strong>de</strong>l objeto.<br />
� También conocido como.<br />
� Objets for state (estados como objetos).<br />
� Motivación.<br />
� TCPConnection para p representar p una conexión <strong>de</strong> red.<br />
� Pue<strong>de</strong> estar en distintos estados: establecida, escuchando y cerrada.<br />
� El efecto <strong>de</strong> cada petición sobre cada objeto <strong>de</strong>pen<strong>de</strong> <strong>de</strong>l estado en el que está.<br />
124
State<br />
�Estructura.<br />
125
Strategy<br />
� Propósito.<br />
� Define una familia <strong>de</strong> algoritmos, encapsula cada uno <strong>de</strong> ellos, y los hace<br />
intercambiables.<br />
� Permite que un algoritmo varíe in<strong>de</strong>pendientemente <strong>de</strong> los clientes que los usan.<br />
� También conocido como.<br />
� Policy (política).<br />
�� Motivación<br />
Motivación.<br />
� Ej.: Algoritmos para dividir en líneas un flujo <strong>de</strong> texto.<br />
� Clases que encapsulen los distintos algoritmos <strong>de</strong> división. Un algoritmo así<br />
encapsulado se <strong>de</strong>nomina estrategia estrategia.<br />
126
Strategy<br />
�Estructura.<br />
127
Command<br />
� Propósito.<br />
�� Encapsula peticiones a objetos objetos.<br />
� Permite parametrizar a los clientes con diferentes peticiones, hacer<br />
cola o llevar un registro <strong>de</strong> peticiones, así como <strong>de</strong>shacer las<br />
peticiones peticiones.<br />
� También conocido como.<br />
� Action, Transaction.<br />
� MMotivación. ti ió<br />
� Framework gráfico tipo MFC. Peticiones <strong>de</strong> los distintos widgets<br />
encapsuladas como objetos.<br />
128
Command<br />
�� MMotivación. ti ió<br />
129
Command<br />
�� EEstructura. t t<br />
130
Chain of Resposibility<br />
� Propósito.<br />
� Evita acoplar el emisor <strong>de</strong> una petición a su receptor, dando a más<br />
<strong>de</strong> un objeto la posibilidad <strong>de</strong> respon<strong>de</strong>r a la petición.<br />
�� Enca<strong>de</strong>na los objetos receptores y pasa la petición a través <strong>de</strong> la<br />
ca<strong>de</strong>na hasta que es procesada por algún objeto.<br />
� Motivación.<br />
� Ej.: ayuda sensible al contexto en una GUI.<br />
� Si no existe ayuda para una parte <strong>de</strong> la interfaz, se muestra ayuda<br />
para p una pparte más ggeneral.<br />
131
Chain of Resposibility<br />
�Motivación.<br />
132
Chain of Resposibility<br />
�Estructura.<br />
133
Indice<br />
�� IIntroducción. t d ió<br />
� <strong>Patrones</strong> <strong>de</strong> Creación.<br />
�� <strong>Patrones</strong> Estructurales.<br />
Estructurales<br />
� <strong>Patrones</strong> <strong>de</strong> Comportamiento.<br />
�Conclusiones<br />
�Conclusiones.<br />
� Bibliografía.<br />
134
Conclusiones<br />
�� Los patrones <strong>de</strong> diseño capturan el conocimiento que<br />
tienen los expertos a la hora <strong>de</strong> diseñar.<br />
� Los patrones ayudan a generar software “maleable”<br />
(software que soporta y facilita el cambio, la reutilización<br />
y la mejora) mejora).<br />
� Los patrones <strong>de</strong> diseño son guías, no reglas rigurosas.<br />
� Cada patrón <strong>de</strong>scribe la solución a problemas que se<br />
repiten una y orta vez en nuestro entorno entorno, <strong>de</strong> forma que<br />
se pue<strong>de</strong> usar esa solución todas las veces que haga<br />
falta.<br />
135
Indice<br />
�� IIntroducción. t d ió<br />
� <strong>Patrones</strong> <strong>de</strong> Creación.<br />
�� <strong>Patrones</strong> Estructurales.<br />
Estructurales<br />
� <strong>Patrones</strong> <strong>de</strong> Comportamiento.<br />
�� Conclusiones<br />
Conclusiones.<br />
�Bibliografía.<br />
136
Bibliografía<br />
� “D “Design i patterns, tt elements l t of f reusable bl object- bj t<br />
oriented software”. Gamma, Helm, Jonhnson,<br />
Vlissi<strong>de</strong>s Vlissi<strong>de</strong>s. Addison Wesley, Wesley 1995 (traducido al<br />
español en 2003).<br />
� “Applying UML and Patterns. An introduction to<br />
Object Object-Oriented Oriented Analysis and Design and<br />
Iterative Development. 3rd Edition.” Craig<br />
Larman Larman. Prentice Hall Hall.2005. 2005<br />
�� http://hillsi<strong>de</strong> http://hillsi<strong>de</strong>.net/<br />
net/<br />
137