03.12.2012 Views

Patrones de Diseño Ejemplo

Patrones de Diseño Ejemplo

Patrones de Diseño Ejemplo

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!