Patrones de Diseño

137
Patrones de Diseño Tema 7 TACC II Grupo 46 1 TACC II Curso 2008/09

Transcript of Patrones de Diseño

Page 1: Patrones de Diseño

Patrones de DiseñoTema 7

TACC II

Grupo 46

111

TACC IICurso 2008/09

Page 2: Patrones de Diseño

IndiceIndice

I t d ióIntroducción.Patrones.Descripción de los Patrones.Ejemplo: Patrones en el MVC de Smalltalk.El catálogo de patrones.

Patrones de Creación.Patrones Estructurales.Patrones de Comportamiento.C l iConclusiones.Bibliografía.

222

Page 3: Patrones de Diseño

IntroducciónIntroducción

Di ñ ífi l bl lDiseño específico para el problema, pero general como para poder adecuarse a futuros requisitos y problemas.

Evitar el rediseño en la medida de lo posible.

Evitar resolver cada problema partiendo de cero.

Reutilizar soluciones que han sido útiles en el pasado.

Patrones recurrentes de clases y comunicación entre objetos en muchas soluciones de diseño.

3

Page 4: Patrones de Diseño

PatrónPatrón

Un esquema que se usa para solucionar un problemaUn esquema que se usa para solucionar un problema.

El esquema ha sido probado extensivamente, y haEl esquema ha sido probado extensivamente, y ha funcionado. Se tiene experiencia sobre su uso.

E i t h d i iExisten en muchos dominios:Novelas y el cine: “héroe trágico”, “comedia romántica”, etc.Arte.Ingenierías.Arquitectura.

Christopher Alexander. “A Pattern Language: Towns, Buildings, p g g , g ,Construction”. 1977.http://www.patternlanguage.com

4

Page 5: Patrones de Diseño

Patrones de DiseñoPatrones de Diseño

R tili di ñ b t t i l d t llReutilizar diseños abstractos que no incluyan detalles de la implementación.

Un patrón es una descripción del problema y la esencia de su solución, que se puede reutilizar en casos q pdistintos.

E l ió d d bl úEs una solución adecuada a un problema común.

A i d i t ió bj t l i i iAsociado a orientación a objetos, pero el principio general es aplicable a todos los enfoques de diseño software.

5

Page 6: Patrones de Diseño

Patrones de Diseño

D t l i i l di ñ

Patrones de Diseño

Documentar la experiencia en el diseño, en forma de un catálogo de patrones.

Categorías de patrones:

De creación: implica el proceso de instanciar objetos.

Estructurales: composición de objetos.

De comportamiento cómo se com nican los objetosDe comportamiento: cómo se comunican los objetos, cooperan y distribuyen las responsabilidades para lograr sus objetivos.

6

Page 7: Patrones de Diseño

Patrones de DiseñoEstructura de un patrón

N b d l t óNombre del patrón.Describe el problema de diseño, junto con sus soluciones y consecuencias. V b l i d di ñVocabulario de diseño.

Problema.Describe cuándo aplicar el patrón. Explica el problema y su contexto.

Solución.Elementos que forman el diseño, relaciones, responsabilidades.Elementos que forman el diseño, relaciones, responsabilidades.No un diseño concreto, sino una plantilla que puede aplicarse en muchas situaciones distintas.

ConsecuenciasConsecuencias.Resultados, ventajas e inconvenientes de aplicar el patrón.P.ej.: relación entre eficiencia en espacio y tiempo; cuestiones de implementación etc

7

implementación, etc.

Page 8: Patrones de Diseño

Patrones de DiseñoEjemplo: MVC de Smalltalk

Modelo/Vista/Controlador.40

A

C

D

10

20

30

40

A B C DX 60 20 15 5Y 40 25 15 20

B 0A B C D

Y 40 25 15 20Z 10 10 20 60

ModeloA: 40%B: 25%C 15%

8

C: 15%D: 20%

Page 9: Patrones de Diseño

Patrones de Diseño

S l bj t l d t ( d l )

Ejemplo: MVC de Smalltalk

Separar los objetos con los datos (modelo), sus visualizaciones (vistas) y el modo en que la interfaz reacciona ante la entrada al usuario (controlador).( )

Separar estos componentes, para aumentar la p p pflexibilidad y reutilización.

D l i d d l di l dDesacoplar vistas de modelos, mediante un protocolo de subscripción/notificación.

Cada vez que cambian los datos del modelo, avisar a las vistas que dependen de él. Estas se actualizan.

9

q p

Page 10: Patrones de Diseño

Patrones de Diseño

Patrón Observer más general (dependencias entre

Ejemplo: MVC de Smalltalk

Patrón Observer, más general (dependencias entre objetos).

Las vistas se pueden anidar: Vistas compuestas y simples.

Generalización: Patrón CompositeGeneralización: Patrón Composite.

La relación entre la vista y el controlador: patrón St t ( bj t t l it )Strategy (un objeto que representa un algoritmo).

Otros patrones:Otros patrones:Factory Method: especifica la clase controlador predeterminada para una vista.Decorator: Añade capacidad de desplazamiento a una vista

10

Decorator: Añade capacidad de desplazamiento a una vista.

Page 11: Patrones de Diseño

El catálogo de patronesEl catálogo de patronesPropósito

Creación Estructurales De Comportamiento

Clase Factory Method Adapter (de clases) Interpreter.Template MethodTemplate Method.

Ám Objeto Abstract Factory Adapter (de objetos). Chain of Responsibility.m

bito

jBuilderPrototypeSingleton

Bridge.Composite.Decorator.

Command.Iterator.Mediator.

Facade.Flyweight.Proxy.

Memento.Observer.State.

11

Proxy. State.Strategy.Visitor.

Page 12: Patrones de Diseño

El catálogo de patronesRelaciones entre

los patrones.

12

Page 13: Patrones de Diseño

IndiceIndice

IntroducciónIntroducción.Patrones de Creación.

SingletonSingleton.Abstract Factory.Factory Method.

Patrones Estructurales.Patrones de Comportamiento.Concl sionesConclusiones.Bibliografía.

131313

Page 14: Patrones de Diseño

Patrones de CreaciónPatrones de Creación

Ab t l d i t i ióAbstraen el proceso de instanciaciónAyudan a que el sistema sea independiente de cómo se crean componen y representan loscómo se crean, componen y representan los objetos.Flexibilizan:Flexibilizan:

qué se creaquién lo creacómo se creacuándo se crea

Permiten configurar un sistema:Permiten configurar un sistema:estáticamente (compile-time)dinámicamente (run-time)

14

( )

Page 15: Patrones de Diseño

SingletonSingleton

I t ióIntención.Asegurar que una clase tiene una única instancia y proporciona un punto de acceso global a dicha instancia.

Motivación.Hay veces que es importante asegurar que una clase tenga una sola instancia por ejemplo:sola instancia, por ejemplo:

Un gestor de ventanasUna única cola de impresiónUn único sistema de ficherosUn único sistema de ficherosUn único fichero de log, o un único repositorio.

¿Cómo asegurarlo? una variable global hace el objeto accesible pero se puede instanciar varias vecesaccesible, pero se puede instanciar varias veces.Responsabilidad de la clase misma: actuar sobre el mensaje de creación de instancias

15

Page 16: Patrones de Diseño

SingletonSingleton

Aplicabilidad.Cuando debe haber una sola instancia, y debe ser accesible a losclientes desde un punto de acceso conocido.clientes desde un punto de acceso conocido.Cuando la única instancia debe ser extensible mediantesubclasificación, y los clientes deben ser capaces de usar unainstancia extendida sin modificar su códigoinstancia extendida sin modificar su código.

Estructura.

Singleton static Singleton uniqueInstancesingletonData

static Singleton Instance ()SingletonOperation ()GetSingletonData ()

return uniqueInstance

16

Page 17: Patrones de Diseño

SingletonSingletonParticipantes:p

Singleton:Define una operación de clase, llamada “Instance” que deja a los clientesacceder a la única instancia.Puede ser responsable de crear su única instancia.

Colaboraciones:Los clientes acceden a la instancia de un Singleton a través de laoperación “Instance”.

Consecuencias:Acceso controlado a la única instancia.Espacio de nombre reducido. Mejora sobre el uso de variablesglobales.Permite el refinamiento de operaciones y la representación. Se puedep y p psubclasificar de la clase Singleton y configurar la aplicación con unainstancia de esta clase.Fácil modificación para permitir un número variable de instancias.

17Más flexible que las operaciones de clase.

Page 18: Patrones de Diseño

SingletonSingletonImplementación:Implementación:

class Singleton {private:p

static Singleton* _instance;void otherOperations();

protected: Singleton();

public: static Singleton* getInstance();

}};

Singleton* Singleton::_instance = 0;

Singleton* Singleton::getInstance() {if (_instance == 0 )

instance = new Singleton;18

_instance = new Singleton;return _instance;

}

Page 19: Patrones de Diseño

Ejemplo#include "stdafx.h"#include <iostream>using namespace std; Ejemploclass Maze{

int x, y;public:

M (i i ) ( ) ( ) {}Maze(int x, int y) : x(x), y(y) {}};

class MazeFactory {blipublic:

static MazeFactory* Instance();// existing interface goes hereMaze * createMaze(int x, int y) { return new Maze(x, y); };

t t dprotected:MazeFactory() {};

private:static MazeFactory* _instance;

}};

MazeFactory* MazeFactory::_instance = 0;

M F t * M F t I t () {MazeFactory* MazeFactory::Instance () {if (_instance == 0) _instance = new MazeFactory;return _instance;

}

19void main(){

Maze * m = MazeFactory::Instance()->createMaze(10,10);}

Page 20: Patrones de Diseño

SingletonImplementación:

Creación de una subclase de singleton.D t i é i l t l ió “I t ”Determinar qué singleton queremos usar en la operación “Instance”.Registro de objetos singleton.

class Singleton {public:

static void Register(const char* name, Singleton*);static Singleton* Instance();static Singleton Instance();

protected:static Singleton* Lookup(const char* name);

private:static Singleton* _instance;static List<NameSingletonPair>* _registry;

};Si l t * Si l t I t () {Singleton* Singleton::Instance () {

if (_instance == 0) {const char* singletonName =getenv("SINGLETON");// user or environment supplies this at startup

20

// use o e o e supp es s a s a up_instance = Lookup(singletonName); // Lookup returns 0 if there's no such singleton

}return _instance; }

Page 21: Patrones de Diseño

SingletonSingleton

¿Dónde se registra la clase?Una posibilidad es en el constructor.

MySingleton::MySingleton() {// ...Singleton::Register("MySingleton", this);

Entonces hay que instanciar la clase!

g g ( y g )}

Se puede crear una instancia global:static MySingleton theSingleton;

21

Page 22: Patrones de Diseño

SingletongEjemplo

MazeFactory* MazeFactory::Instance () {class MazeFactory {public:

static MazeFactory* Instance();// existing interface goes here

MazeFactory MazeFactory::Instance () {if (_instance == 0) {const char* mazeStyle = getenv("MAZESTYLE");if (strcmp(mazeStyle, "bombed") == 0)

i t B b dM F tg g

protected:MazeFactory();

private:static MazeFactory* instance;

_instance = new BombedMazeFactory;} else if (strcmp(mazeStyle, "enchanted") == 0)

_instance = new EnchantedMazeFactory;// ... other possible subclassesstatic MazeFactory _instance;

};

MazeFactory* MazeFactory::_instance = 0;

} else_instance = new MazeFactory;

return _instance;}}

22

Page 23: Patrones de Diseño

Abstract FactoryAbstract Factory

P ó itPropósito.Proporciona una interfaz para crear familias de objetosrelacionados o que dependen entre sí, sin especificar suslclases concretas.

También Conocido Como.KitKit.

Motivación.Ej.: un framework para la construcción de interfaces de usuario

“ f ” ( fque permita varios “look and feel” (ej.: Motif y PresentationManager).

Una clase abstracta WidgetFactory con la interfaz para crearcada tipo de widgetcada tipo de widget.Una clase abstracta para cada tipo de widget. Subclasesconcretas que implementan cada widget concreto.De esta manera los clientes son independientes del look

23

De esta manera, los clientes son independientes del lookand feel concreto.

Page 24: Patrones de Diseño

Abstract FactoryAbstract Factory

Motivación.

WidgetFactory

CreateScrollBar()CreateWindow()

Client

Window

Productos

MotifWidgetFactory PMWindowFactoryMotifWindowPMWindow

Familias

MotifWidgetFactory

CreateScrollBar()CreateWindow()

PMWindowFactory

CreateScrollBar()CreateWindow()

ScrollBar

MotifScrollBarPMScrollBar

24

Page 25: Patrones de Diseño

Abstract FactoryAbstract Factory

Aplicabilidad. Usar este patrón cuando:un sistema que deba ser independiente de cómo se

dcrean, componen y representan sus productos.un sistema que deba ser configurado con una familia deproductos entre variasproductos entre varias.una familia de objetos producto relacionados que estádiseñada para ser usada conjuntamente y es necesariodiseñada para ser usada conjuntamente, y es necesariohacer cumplir esta restricción.se quiere proporcionar una biblioteca de clasesq p pproductos, y sólo se quiere revelar sus interfaces, no suimplementación.

25

Page 26: Patrones de Diseño

Abstract FactoryAbstract Factory

Estructura:

AbstractFactory

createProductA ()

ClientProductos()

createProductB () AbstractProductA

Familias

ConcreteFactory1

createProductA ()createProductB ()

ConcreteFactory2

createProductA ()createProductB ()

AbstractProductB

ProductA1ProductA2

createProductB () createProductB ()

ProductB1ProductB2

26

Page 27: Patrones de Diseño

Abstract FactoryAbstract FactoryParticipantes:p

AbstractFactory. Declara una interfaz para operaciones quecrean objetos producto abstractos.ConcreteFactory. Implementa las operaciones para crear objetosy p p p jproducto concretos.AbstractProduct. Declara una interfaz para un tipo de objetoproducto.ConcreteProduct. Define un objeto producto para que sea creadopor la fábrica correspondiente.Client. Sólo usa interfaces declaradas por las clasesAb t tF t Ab t tP d tAbstractFactory y AbstractProduct.

Colaboraciones.Normalmente sólo se crea una única instancia de una claseConcreteFactory en tiempo de ejecución. Esta fábrica concretacrea objetos producto que tienen una determinadaimplementación.Ab t tF t d l l ió d bj t d t

27

AbstractFactory delega la creación de objetos producto en susubclase ConcreteFactory.

Page 28: Patrones de Diseño

Abstract Factory

C i

Abstract Factory

Consecuencias.Aísla las clases concretas. Ayuda a controlarlas clases de objetos que crea una aplicación.Aísla a los clientes de las clases deimplementaciónimplementación.Facilita el reemplazo de familias de productos.P l i t i t d t (Promueve la consistencia entre productos (quela aplicación use objetos de una sola familia ala vez)la vez).Es difícil añadir un nuevo producto.

28

Page 29: Patrones de Diseño

Abstract FactoryAbstract FactoryEjemplo

Ejemplo: aplicación para construir un coche a partirde unas partes (motor, chasis, ...)

t d l t d l i (f ili )todos los componentes de la misma marca (familia)hay múltiples marcas (Ford, Toyota, Opel, ...)es responsabilidad del cliente ensamblar las piezasp p

Car

ToyotaCarFordCar PorscheCarCarPart

CarBodyCarEngine

29ToyotaBodyFordBody PorscheBodyToyotaEngineFordEngine PorscheEngine

Page 30: Patrones de Diseño

Abstract FactoryAbstract FactoryEjemplo (ii)

¿Cómo lo haríamos sin utilizar el patrón Abstract Factory?¿Cómo lo haríamos sin utilizar el patrón Abstract Factory?En un método del cliente:

CrearCoche (string marca) {

if (marca == “ford”)FordCar coche = new FordCar ()

El código del cliente decide qué clase de coche construir (bien)else if (marca == “toyota”)

ToyotaCar coche = new ToyotaCar ()else …;

coche construir (bien) y qué subpartesinstanciar (mal). Puede

if (marca == “ford”)FordEngine motor = new FordEngine ()

else if (marca == “toyota”)ToyotaEngine motor = new ToyotaEngine ()

cometerse el error de ensamblar partes de distintas familiaselse …;

coche.add (motor);...

distintas familias.

30return coche;}

Page 31: Patrones de Diseño

Abstract FactoryAbstract FactoryEjemplo (iii)

CarPartFactory

makeCar ()makeBody ()

Client

CarBody

Productosy ()

makeEngine ()CarBody

ToyotaBodyFordBodyFamilias

ToyotaFactory

makeCar ()

FordFactory

makeCar ()

CarEngine

makeCar ()makeBody ()makeEngine ()

makeCar ()makeBody ()makeEngine () ToyotaEngineFordEngine

Car

31ToyotaCarFordCar

Page 32: Patrones de Diseño

Abstract FactoryAbstract FactoryEjemplo (iv)

Utilizando el patrón, éste fuerza a que todos los productos sean de lamisma familia, una vez establecida ésta por el cliente.

El patrón permite separar la elección de la familia (la marca delcoche) del proceso de instanciar las partes.

En el cliente:

Car hacerCoche () {Car coche=familia.makeCar();coche.addEngine (familia.makeEngine());coche.addBody (familia.makeBody ());...

t h32

return coche;}

Page 33: Patrones de Diseño

Abstract Factory

familia contiene una instancia de una marca de coche

Abstract FactoryEjemplo (v)

familia contiene una instancia de una marca de coche.¿Cómo se instancia familia?

class CrearCoche {CarPartFactory * familia;y ;

Car hacerCoche () {Car coche=familia->makeCar();coche.addEngine (familia->makeEngine());

//presenta por pantalla la selecciónclass CrearCocheGUI : public CFrameWnd {//….

id O B tt Cli k d () { g ( g ());coche.addBody (familia->makeBody ());...return coche;

}

void OnButtonClicked () {string familiasel;CrearCoche assembler;Car coche;// }

static CrearCoche using (CarPartFactory * f) {CrearCoche l;l.factory (f);

//…if (familiasel == “ford”)

assembler=CrearCoche::using (new FordFactory())else if (familiasel == “toyota”)

bl C C h i ( T t F t ()) y ( );return l;

}

void factory (CarPartFactory * f) {

assembler=CrearCoche::using (new ToyotaFactory())else …;

coche = assembler.hacerCoche();}

33

y ( y ) {familia=f;

}}

}}

Page 34: Patrones de Diseño

Abstract FactoryAbstract FactoryOtro Ejemplo: Laberinto

MazeFactory

+MakeMaze(): Maze

MazeGame

+CreateMaze(MazeFactory): Maze+MakeWall(): Wall+MakeRoom(int n): Room+MakeDoor(Room r1, Room r2): Door

Maze Wall RoomEnchantedMazeFactory

+MakeRoom(int n): EnchantedRoom+MakeDoor(Room r1, Room r2): DoorNeedingSpell

EnchantedRoom

BombedWall

DoorBombedMazeFactory

RoomWithABomb

34DoorNeedingSpell

+MakeRoom(int n): RoomWithABomb+MakeWall(): BombedWall

Page 35: Patrones de Diseño

Abstract FactoryAbstract FactoryOtro Ejemplo: Laberinto

class MazeFactory {public:

MazeFactory();i t l M * M k M () tvirtual Maze* MakeMaze() const

{ return new Maze; }virtual Wall* MakeWall() const{ return new Wall; }{ ; }virtual Room* MakeRoom(int n) const{ return new Room(n); }virtual Door* MakeDoor(Room* r1, Room* r2) const{ t D ( 1 2) }{ return new Door(r1, r2); }

};

35

Page 36: Patrones de Diseño

Abstract FactoryAbstract FactoryOtro Ejemplo

Maze* MazeGame::CreateMaze (MazeFactory& factory) {Maze* aMaze = factory.MakeMaze();Room* r1 = factory.MakeRoom(1);Room r1 factory.MakeRoom(1);Room* r2 = factory.MakeRoom(2);Door* aDoor = factory.MakeDoor(r1, r2);aMaze->AddRoom(r1);M AddR ( 2)aMaze->AddRoom(r2);

r1->SetSide(North, factory.MakeWall());r1->SetSide(East, aDoor);r1->SetSide(South, factory.MakeWall());( , y ());r1->SetSide(West, factory.MakeWall());r2->SetSide(North, factory.MakeWall());r2->SetSide(East, factory.MakeWall());2 >S tSid (S th f t M k W ll())r2->SetSide(South, factory.MakeWall());

r2->SetSide(West, aDoor);return aMaze;

}

36

}

Page 37: Patrones de Diseño

Abstract FactoryAbstract FactoryOtro Ejemplo

class EnchantedMazeFactory : public MazeFactory {public:

EnchantedMazeFactory();virtual Room* MakeRoom(int n) constvirtual Room* MakeRoom(int n) const{ return new EnchantedRoom(n, CastSpell()); }virtual Door* MakeDoor(Room* r1, Room* r2) const

{ return new DoorNeedingSpell(r1, r2); { g p ( , );}

protected:Spell* CastSpell() const;

};};// Make it possible to have rooms with bombs

Wall* BombedMazeFactory::MakeWall () const {MazeGame game;BombedMazeFactory factory;Wall BombedMazeFactory::MakeWall () const {

return new BombedWall;}Room* BombedMazeFactory::MakeRoom(int n) const {

t R WithAB b( )

y y;game.CreateMaze(factory);

37

return new RoomWithABomb(n);}

Page 38: Patrones de Diseño

Factory MethodFactory Method

P ó itPropósito.Define una interfaz para crear un objeto, pero deja quesean las subclases quienes decidan qué clase instanciar.q qPermite que una clase delegue en sus subclases lacreación de objetos.

También Conocido Como.También Conocido Como.Virtual Constructor.

Motivación.Ej.: un framework que pueda presentar distintos tipos dedocumentos (similar a MFCs).

Dos abstracciones clave: aplicación y documento (ambasp y (clases abstractas). Hay que subclasificarlas.La clase aplicación no sabe qué subclase documentoinstanciar.

38

Page 39: Patrones de Diseño

Factory MethodFactory Method

Motivación.Se le llama “factory method” (métodode fabricación)

Documento

+Abrir()

Aplicacion

+CrearDocumento()

docs1..*

Documento * doc = CrearDocumento()d h b k(d )b ()

+Cerrar()+Guardar()+Deshacer()

CrearDocumento()+NuevoDocumento()+AbrirDocumento()

docs.push_back(doc)doc->Abrir()

MiDocumentoMiAplicacion

C D t ()return new MiDocumento

+CrearDocumento()

39

Page 40: Patrones de Diseño

Factory MethodFactory Method

A li bilid d U ó dAplicabilidad. Usar este patrón cuando:Una clase no puede prever la clase de los objetos que tiene que crear.Una clase quiere que sean sus subclases las que decidan qué objetosUna clase quiere que sean sus subclases las que decidan qué objetos crean.Las clases delegan la responsabilidad en una de entre varias clases auxiliares y queremos localizar qué subclase concreta es en la que seauxiliares, y queremos localizar qué subclase concreta es en la que se delega.

Estructura.Creator

P d t

Creator

+FactoryMethod()+AnOperation()

//…product = factoryMethod()//…Product +AnOperation()

C t P d t C t C t

//…

40

ConcreteProduct ConcreteCreator

+FactoryMethod()return new ConcreteProduct

Page 41: Patrones de Diseño

Factory Method

P ti i t

Factory Method

Participantes.Product (Documento). Define la interfaz de los objetos que creael factory method.yConcreteProduct (MiDocumento). Implementa la interfaz delproducto.Creator (Aplicacion) Declara el factory method Puede tambiénCreator (Aplicacion). Declara el factory method. Puede tambiéndar una implementación por defecto del factory method, quedevuelve un objeto de una clase por defecto.ConcreteCreator (MiAplicacion) Sobreescribe el factoryConcreteCreator (MiAplicacion). Sobreescribe el factorymethod para devolver una instancia de ConcreteProduct.

Colaboraciones.El creator se apoya en sus subclases para definir el método defabricación de manera que éste devuelva una instancia delConcreteProduct adecuado.

41

Page 42: Patrones de Diseño

Factory Method

Consecuencias

Factory Method

Consecuencias.Los métodos de fabricación eliminan la necesidad deligar clases específicas de la aplicación a nuestrog p pcódigo.

El código sólo trata con la interfaz Product puedeEl código sólo trata con la interfaz Product, puedefuncionar con cualquier clase ConcreteProductdefinida por el usuario.

Proporciona enganches para las subclases. Crearobjetos con un método de fabricación es más flexibleobjetos con un método de fabricación es más flexibleque hacerlos directamente.

El f t th d h k th d l42

El factory method es un hook method para que lassubclases den una versión extendida del código.

Page 43: Patrones de Diseño

Factory MethodFactory Method

Consecuencias.Figure ManipulatorFigure Manipulator

+DownClick()+Drag()

…+CreateManipulator() g()

+UpClick()p ()

LineManipulator

+DownClick()+Drag()

TextManipulator

+DownClick()+Drag()

LineFigure

…+CreateManipulator()

TextFigure

…+CreateManipulator() +Drag()

+UpClick()+Drag()+UpClick()

+CreateManipulator() +CreateManipulator()

43

Page 44: Patrones de Diseño

Factory Method

I l t ió

Factory Method

Implementación.Dos variantes principales:

Cuando la clase Creator es abstracta y noproporciona implementación para el método defabricación que declarafabricación que declara.Cuando la clase Creator es concreta y proporcionauna implementación predeterminada para el métodode fabricación.

Métodos de fabricación parametrizados:Q l f t th d i ti dQue los factory methods creen varios tipos deproducto. El método recibe un parámetro queidentifica el tipo de objeto a crear.

44

p j

Page 45: Patrones de Diseño

Factory MethodFactory Method

Implementación.class Creator {{public:

Product* GetProduct();protected:

virtual Product* CreateProduct(); // factory methodprivate:

Product* _product;};

Product* Creator::GetProduct () {if ( d t 0) {if (_product == 0) {

_product = CreateProduct();}ret rn prod ct

45

return _product;}

Page 46: Patrones de Diseño

Factory MethodFactory Method

Implementación. Se pueden usar plantillas para evitar la herencia (múltiples subclases de Creator).

class Creator {public:

virtual Product* CreateProduct() = 0; // El cliente proporciona sólo la clase del// producto, no necesita hacer una

// pure virtual factory method};template <class TheProduct>class StandardCreator: public Creator {

// nueva clase que herede de creator.class MyProduct : public Product {public:

MyProduct();class StandardCreator: public Creator {public:

virtual TheProduct* CreateProduct(); };

MyProduct();// ...

};StandardCreator<MyProduct> myCreator;

template <class TheProduct>TheProduct* StandardCreator<TheProduct>::CreateProduct () {

46

StandardCreator<TheProduct>::CreateProduct () {return new TheProduct;

}

Page 47: Patrones de Diseño

Factory MethodFactory MethodEjemplo

class MazeGame {public:

Maze* CreateMaze();

Maze* MazeGame::CreateMaze () {Maze* aMaze = MakeMaze();Room* r1 = MakeRoom(1);();

// factory methods:virtual Maze* MakeMaze() const{ return new Maze; }virtual Room* MakeRoom(int n) const

Room r1 MakeRoom(1);Room* r2 = MakeRoom(2);Door* theDoor = MakeDoor(r1, r2);aMaze->AddRoom(r1);M AddR ( 2)virtual Room* MakeRoom(int n) const

{ return new Room(n); }virtual Wall* MakeWall() const{ return new Wall; }

aMaze->AddRoom(r2);r1->SetSide(North, MakeWall());r1->SetSide(East, theDoor);r1->SetSide(South, MakeWall());{ }

virtual Door* MakeDoor(Room* r1, Room* r2) const{ return new Door(r1, r2); }

};

( , ());r1->SetSide(West, MakeWall());r2->SetSide(North, MakeWall());r2->SetSide(East, MakeWall());2 >S tSid (S th M k W ll())r2->SetSide(South, MakeWall());

r2->SetSide(West, theDoor);return aMaze;

}

47

}

Page 48: Patrones de Diseño

Factory MethodFactory MethodEjemplo

class BombedMazeGame : public MazeGame {public:

BombedMazeGame();virtual Wall* MakeWall() constvirtual Wall MakeWall() const{ return new BombedWall; }virtual Room* MakeRoom(int n) const{ return new RoomWithABomb(n); }

};

class EnchantedMazeGame : public MazeGame {blipublic:

EnchantedMazeGame();virtual Room* MakeRoom(int n) const{ return new EnchantedRoom(n, CastSpell()); }{ ( , p ()); }virtual Door* MakeDoor(Room* r1, Room* r2) const{ return new DoorNeedingSpell(r1, r2); }

protected:S ll* C tS ll() t

48

Spell* CastSpell() const;};

Page 49: Patrones de Diseño

IndiceIndice

I t d ióIntroducción.Patrones de Creación.

P t E t t lPatrones Estructurales.Composite.Co pos teFacade.ProProxy.Adapter.

Patrones de Comportamiento.Conclusiones.

494949Bibliografía.

Page 50: Patrones de Diseño

Patrones EstructuralesPatrones Estructurales

E t bl ó l bj tEstablecen cómo se componen clases y objetospara formar estructuras mayores queimplementan nueva funcionalidadimplementan nueva funcionalidad.Los patrones de clase usan la herencia paracomponer interfaces o implementaciones (ej :componer interfaces o implementaciones (ej.:Adapter).Los patrones de objeto describen maneras deLos patrones de objeto, describen maneras decomponer objetos para implementar nuevafuncionalidadfuncionalidad.

Flexibilidad, ya que se puede cambiar la configuraciónen tiempo de ejecución.

50

Page 51: Patrones de Diseño

CompositeCompositePropósito.

componer objetos en estructuras arborescentes pararepresentar jerarquías parte-conjunto.

M ti ióMotivación.Aplicaciones gráficas. Manipulación de grupos de figuras demanera uniformemanera uniforme.

Grafico

dibuja ()graficos*

dibuja ()

Dibujo

dibuja ()añade (Grafico g)

Linea

dibuja ()

Rectangulo

dibuja ()

Texto

dibuja () para todo g en graficosg.dibuja ()

51

elimina (Grafico g)obtenHijo (int) añadir g a la lista de

graficos:graficos.addElement (g)

Page 52: Patrones de Diseño

CompositeCompositeUna instancia en tiempo de ejecución:

:Dibujo

Una instancia en tiempo de ejecución:

:Linea :Texto:Dibujo

graficos graficos graficos

:Linea :Texto:Dibujo

graficosgraficos

:Rectangulo :Texto

Page 53: Patrones de Diseño

CompositeAplicabilidad. Usar el patrón cuando:

Composite

Se quieren representar jerarquías todo/parte de objetos.Se quiere que los clientes ignoren la diferencia entre composiciones de objetos y objetos individuales. Los clientes tratarán todos los objetos en j y j jla estructura compuesta de manera uniforme.

Estructura.

Client Component

+ Operation()+ Add(Component)

children*

( p )+ Remove(Component)+ GetChild(int)

Composite

+ Operation() forall g in children:O ti ()

Leaf

+ Operation()

53

p ()+ Add(Component)+ Remove(Component)+ GetChild(int)

g.Operation()+ Operation()

Page 54: Patrones de Diseño

CompositeCompositeParticipantes.p

Component (Grafico).Declara la interfaz de los objetos de la composición.Implementa el comportamiento por defecto de la interfaz común ap p ptodas las clases.Declara las interfaces para acceder y gestionar los hijos.(opcional) Define una interfaz para acceder al padre de un componenteen la estructura recursiva y la implementa si es apropiadoen la estructura recursiva y la implementa, si es apropiado.

Leaf (Linea, Rectangulo, …).Representa objetos hoja en la composición. Una hoja no tiene hijos.Define el comportamiento de los objetos primitivos en la composiciónDefine el comportamiento de los objetos primitivos en la composición.

Composite (Dibujo)Define el comportamiento de los objetos con hijos en la composición.Almacena componentes hijoAlmacena componentes hijo.Implementa operaciones relacionadas con los hijos de la interfaz deComponent.

Client54

Client.Manipula objetos en la composición a través de la interfaz deComponent.

Page 55: Patrones de Diseño

CompositeCompositeColaboracionesColaboraciones.

Los clientes usan el interfaz de la clase Component parainteraccionar con los objetos de la estructura compuesta.Si l bj t h j t l ti ió di t tSi el objeto es hoja, entonces la petición se cursa directamente.Si el objeto es un Composite, entonces normalmente redirige laspeticiones a sus objetos hijo, quizá realizando operacionesadicionales antes y/o después de la redirección.

Consecuencias. El patron composite:Define jerarquías de objetos primitivos y compuestos CuandoDefine jerarquías de objetos primitivos y compuestos. Cuandoun código cliente espera un objeto simple, se puede reemplazarpor uno compuesto.Simplifica el cliente Se pueden tratar objetos simples ySimplifica el cliente. Se pueden tratar objetos simples ycompuestos de manera uniforme.Facilita añadir nuevos tipos de componente.

55

Puede hacer el diseño demasiado general. Complicado restringirlos tipos de componente de un composite.

Page 56: Patrones de Diseño

CompositeComposite

I l t ió Al d i iImplementación. Algunas decisiones:Referencias explícitas a los padres. En la clase component.Compartir componentes. Útil para ahorrar memoria, pero laCompartir componentes. Útil para ahorrar memoria, pero la gestión de un componente que tiene más de un padre es difícil.Maximizar la interfaz del componente. Declaración de las operaciones de gestión de hijos EquilibrioDeclaración de las operaciones de gestión de hijos. Equilibrio entre seguridad y transparencia:

Declararla en la raíz da transparencia. Es menos seguro porque el cliente puede tratar de hacer cosas sin sentido sobre objetos hojacliente puede tratar de hacer cosas sin sentido sobre objetos hoja.Declararla en la clase compuesto da seguridad, pero perdemos transparencia: leafs y composites tienen interfaces distintas.

A veces es necesario tener en cuenta un orden para los hijosA veces es necesario tener en cuenta un orden para los hijos.¿Quién debe borrar los componentes?¿Cuál es la mejor estructura de datos para almacenar los

?56

componentes?.

Page 57: Patrones de Diseño

CompositeCompositeEjemplo

class Equipment {class Equipment {public:

virtual ~Equipment();const char* Name() { return _name; }i t l W tt P ()virtual Watt Power();

virtual Currency NetPrice();virtual Currency DiscountPrice();virtual void Add(Equipment*);virtual void Add(Equipment );virtual void Remove(Equipment*);virtual Iterator* CreateIterator() {return 0;}

protected:E i t( t h *)Equipment(const char*);

private:const char* _name;

};};

57

Page 58: Patrones de Diseño

Compositeclass FloppyDisk : public Equipment {public:

Ejemplo

pFloppyDisk(const char*);virtual ~FloppyDisk();virtual Watt Power();virtual Currency NetPrice();virtual Currency NetPrice();virtual Currency DiscountPrice();

};

class CompositeEquipment : public Equipment {class CompositeEquipment : public Equipment {public:

virtual ~CompositeEquipment();virtual Watt Power();();virtual Currency NetPrice();virtual Currency DiscountPrice();virtual void Add(Equipment*);virtual void Remove(Equipment*);virtual void Remove(Equipment*);virtual Iterator* CreateIterator();

protected:CompositeEquipment(const char*);

58

p q p ( )private:

List _equipment;};

Page 59: Patrones de Diseño

CompositeCompositeEjemplo

Currency CompositeEquipment::NetPrice () {Iterator* i = CreateIterator();Currency total = 0;for (i->First(); !i->IsDone(); i->Next()) {for (i >First(); !i >IsDone(); i >Next()) {

total += i->CurrentItem()->NetPrice();}delete i;return total;

}

class Chassis : public CompositeEquipment {class Chassis : public CompositeEquipment {public:

Chassis(const char*);virtual ~Chassis();i t l W tt P ()virtual Watt Power();

virtual Currency NetPrice();virtual Currency DiscountPrice();

};

59

};

Page 60: Patrones de Diseño

CompositeCompositeEjemplo

using namespace std;

void main(){

Cabinet* cabinet = new Cabinet("PC Cabinet");Chassis* chassis = new Chassis("PC Chassis");Chassis* chassis = new Chassis( PC Chassis );cabinet->Add(chassis);Bus* bus = new Bus("MCA Bus");bus->Add(new Card("16Mbs Token Ring"));( ( g ))chassis->Add(bus);chassis->Add(new FloppyDisk("3.5in Floppy"));cout << "The net price is " << chassis->NetPrice() << endl;

}}

60

Page 61: Patrones de Diseño

FacadeFacadePropósito.

Proporciona una interfaz unificada para un conjunto de interfaces de unp p jsubsistema.Define una interfaz de alto nivel que hace que el subsistema sea más fácilde usar.

Motivación.Estructurar un sistema en subsistemas ayuda a reducir su complejidad.Un objetivo típico de diseño es minimizar la comunicación y dependenciasUn objetivo típico de diseño es minimizar la comunicación y dependenciasentre subsistemas.Un modo de conseguir esto es introducir un objeto fachada queproporcione una interfaz única y simplificada a los servicios más generalesdel subsistema.

61

Page 62: Patrones de Diseño

FacadeFacade

Motivación.

62

Page 63: Patrones de Diseño

FacadeFacadeAplicabilidad. Usar el patrón cuando:

Queramos proporcionar una interfaz simple a un subsistema complejo.Sólo los clientes que necesitan más personalización necesitarán ir másallá de la fachada.Haya muchas dependencias entre los clientes y las clases queimplementan una abstracción. La fachada desacopla el subsistema desus clientes y otros subsistemas (mejora acoplamiento y portabilidad).sus clientes y otros subsistemas (mejora acoplamiento y portabilidad).Queramos dividir en capas nuestros subsistemas. La fachada es elpunto de entrada a cada subsistema.

E t tEstructura.

63

Page 64: Patrones de Diseño

FacadeFacade

ParticipantesParticipantes.Facade (Compiler).

Sabe qué clases del subsistema son las responsables ante unapeticiónpetición.Delega las peticiones de los clientes en los objetos apropiados delsubsistema.

Clases del Subsistema (Scanner Parser ProgramNodeBuilderClases del Subsistema (Scanner, Parser, ProgramNodeBuilder,CodeGenerator).

Implementan la funcionalidad del subsistema.Realizan las labores encomendadas por el objeto Facade.p jNo tienen referencias al objeto Facade.

Observaciones.Los clientes se comunican en el sistema enviando peticiones alLos clientes se comunican en el sistema enviando peticiones al

objeto Facade, que las reenvía a los objetos apropiados.Los clientes que usan la fachada no tienen que acceder

directamente a los objetos del subsistema.64

directamente a los objetos del subsistema.

Page 65: Patrones de Diseño

FacadeFacade

C iConsecuencias.Oculta a los clientes los componentes del sistema, haciendoel sistema más fácil de usar.Promueve acoplamiento débil entre el subsistema y susclientes.

Elimina dependencias y puede reducir el tiempo deElimina dependencias y puede reducir el tiempo decompilación.

No impide que las aplicaciones usen las clases delsubsistema en caso necesariosubsistema en caso necesario.

Implementación. Factores a tener en cuenta:Reducción del acoplamiento cliente-subsistema. ClaseReducción del acoplamiento cliente subsistema. Clasefacade abstracta, con clases concretas para las diferentesimplementaciones de un subsistema.Clases del subsistema públicas o privadas Uso de espacios

65

Clases del subsistema públicas o privadas. Uso de espaciosde nombres en C++.

Page 66: Patrones de Diseño

FacadeFacadeEjemplo: Una fachada para un sistema de compilación

class Scanner {class Scanner {public:

Scanner(istream&);virtual ~Scanner();i t l T k & S ()virtual Token& Scan();

private:istream& _inputStream;

};};

class Parser {public:

Parser();Parser();virtual ~Parser();virtual void Parse(Scanner&, ProgramNodeBuilder&);

};}

66

Page 67: Patrones de Diseño

Facadeclass ProgramNodeBuilder {

FacadeEjemplo: Una fachada para un sistema de compilación

g {public:

ProgramNodeBuilder();virtual ProgramNode* NewVariable ( const char* variableName ) const;virtual ProgramNode* NewAssignment ( ProgramNode* variablevirtual ProgramNode* NewAssignment ( ProgramNode* variable,

ProgramNode* expression) const;virtual ProgramNode* NewReturnStatement ( ProgramNode* value ) const;virtual ProgramNode* NewCondition ( ProgramNode* condition,g ( g

ProgramNode* truePart, ProgramNode* falsePart ) const;

// ...ProgramNode* GetRootNode();ProgramNode GetRootNode();

private:ProgramNode* _node;

};

67

Page 68: Patrones de Diseño

FacadeEj l U f h d i t d il ióclass ProgramNode {public:

// program node manipulation

Ejemplo: Una fachada para un sistema de compilación

// program node manipulationvirtual void GetSourcePosition(int& line, int& index);// ...// child manipulationvirtual void Add(ProgramNode*);virtual void Remove(ProgramNode*);// ...virtual void Traverse(CodeGenerator&);virtual void Traverse(CodeGenerator&);

protected:ProgramNode();

};class CodeGenerator {public:

virtual void Visit(StatementNode*);i t l id Vi it(E i N d *)virtual void Visit(ExpressionNode*);

// ...protected:

CodeGenerator(BytecodeStream&);

68

CodeGe e a o ( y ecodeS ea &);protected:

BytecodeStream& _output;};

Page 69: Patrones de Diseño

Facadevoid ExpressionNode::Traverse (CodeGenerator& cg) {

Vi it(thi )

FacadeEjemplo: Una fachada para un sistema de compilación

cg.Visit(this);ListIterator i(_children);for (i.First(); !i.IsDone(); i.Next()) {

i.CurrentItem()->Traverse(cg);() ( g);}

}class Compiler { // Clase Facade

blipublic:Compiler();virtual void Compile(istream&, BytecodeStream&);

};};

void Compiler::Compile ( istream& input, BytecodeStream& output ) {Scanner scanner(input);P N d B ild b ildProgramNodeBuilder builder;Parser parser;parser.Parse(scanner, builder);RISCCodeGenerator generator(output);

69

g ( p );ProgramNode* parseTree = builder.GetRootNode();parseTree->Traverse(generator);

}

Page 70: Patrones de Diseño

ProxyProxyPropósitoPropósito.

Proporcionar un representante o substituto de otro objetopara controlar el acceso a este.

También conocido como.Surrogate (substituto).

M ti ióMotivación.Retrasar el coste de creación e inicialización de un objetohasta que sea realmente necesario.qEj.: al abrir un documento, no abrir las imágenes que no seanvisibles.

aTextDocument:

image

anImageProxy:

fileName

anImage:

data

70

en memoria en disco

Page 71: Patrones de Diseño

ProxyProxy

Motivación.

71

Page 72: Patrones de Diseño

ProxyProxy

AplicabilidadAplicabilidad.Cuando hay necesidad de una referencia a un objeto másflexible o sofisticada que un puntero.Proxy Remoto: un representante para un objeto que seencuentra en otro espacio de direcciones.Proxy Virtual: Crea objetos costosos por encargo (ej.:I P )ImageProxy).Proxy de Protección: Controla el acceso al objeto original(permisos de acceso).Referencia inteligente: sustituto de un puntero, que lleva acabo operaciones adicionales cuando se accede a un objeto(ver ejemplo operadores C++):

C t l ú d f iContar el número de referencias.Cargar un objeto persistente en memoria.Bloquear el objeto cuando se accede a él (no modificaciónconcurrente)

72

concurrente).…

Page 73: Patrones de Diseño

ProxyProxyEstructura.Estructura.

73

Page 74: Patrones de Diseño

ProxyProxyParticipantes.

Proxy.Mantiene una referencia que permite al proxy acceder al objeto real.Proporciona una interfaz igual que la del sujeto real.Controla el acceso al sujeto real, y puede ser responsable de crearlo y borrarlo.Otras responsabilidades, dependen del tipo de proxy:

• Proxy Remoto: codifican las peticiones y se las mandan al sujeto• Proxy Remoto: codifican las peticiones, y se las mandan al sujeto.• Proxy virtual: Puede guardar información adicional sobre el sujeto, para

retardar el acceso al mismo.• Proxy de protección: comprueba que el llamador tiene permiso para

realizar la peticiónrealizar la petición.Subject.

Define una interfaz común para el RealSubject y el Proxy, de tal manera que el Proxy se puede usan en vez del RealSubjectmanera que el Proxy se puede usan en vez del RealSubject.

RealSubject.Define el objeto real que el proxy representa.

Colaboraciones74

Colaboraciones.El proxy redirige peticiones al sujeto real cuando sea necesario, dependiendo del tipo de proxy.

Page 75: Patrones de Diseño

ProxyProxyConsecuenciasConsecuencias.

Introduce un nivel de indirección adicional, que tiene muchos posibles usos:

U t d lt l h h d bj t idUn proxy remoto puede ocultar el hecho de que un objeto reside en otro espacio de direcciones.Un proxy virtual puede realizar optimizaciones, como crear objetos bajo demandabajo demanda.Tanto los proxies de protección, como las referencias inteligentes permiten realizar tareas de mantenimiento adicionales cuando se accede a un objetoaccede a un objeto.

Otra optimización: copy-on-write.Copiar un objeto grande puede ser costoso.Si la copia no se modifica no hay necesidad de incurrir en dichoSi la copia no se modifica, no hay necesidad de incurrir en dicho gasto.El sujeto mantiene una cuenta de referencias, sólo cuando se hace una operación que modifica el objeto se copia realmente (ej : clase

75

una operación que modifica el objeto, se copia realmente (ej.: clase String del ejemplo de operadores C++).

Page 76: Patrones de Diseño

Proxyclass Image;extern Image* LoadAnImageFile(const char*);Proxy

Implementación

// external functionclass ImagePtr {public:

ImagePtr(const char* imageFile);Implementación.Se pueden explotar lassiguientes características del l j

ImagePtr(const char imageFile);virtual ~ImagePtr();virtual Image* operator->();virtual Image& operator*();

los lenguajes:Sobrecargar el operador deacceso a miembros -> enC++

private:Image* LoadImage();

private:Image* image;C++. Image _image;const char* _imageFile;

};ImagePtr::ImagePtr (const char* theImageFile) {

_imageFile = theImageFile;_image = 0;

}Image* ImagePtr::LoadImage () {Image ImagePtr::LoadImage () {

if (_image == 0) {_image = LoadAnImageFile(_imageFile);

}

76

return _image;}

Page 77: Patrones de Diseño

ProxyProxyImage* ImagePtr::operator-> () {Image ImagePtr::operator () {

return LoadImage();}Image& ImagePtr::operator* () {

t *L dI ()return *LoadImage();}

ImagePtr image = ImagePtr("anImageFileName");image->Draw(Point(50, 100));// (image.operator->())->Draw(Point(50, 100))

Sobrecargar “->” no funciona si necesitamos saber a qué operación se llama: entonces hay que definir dichar operación en el proxy y redirigir la llamadallamada.A veces no hace falta que el proxy conozca el tipo concreto del sujeto real (si es suficiente con la interfaz de la clase abstracta Subject).

77

Page 78: Patrones de Diseño

ProxyProxyEjemplo: Un Proxy Virtual

class Graphic {public:public:

virtual ~Graphic();virtual void Draw(const Point& at) = 0;virtual void HandleMouse(Event& event) = 0;virtual const Point& GetExtent() = 0;virtual void Load(istream& from) = 0;virtual void Save(ostream& to) = 0;

protected:pGraphic();

};

class Image : public Graphic {public:

Image(const char* file); // loads image from a filevirtual ~Image();virtual void Draw(const Point& at);virtual void Draw(const Point& at);virtual void HandleMouse(Event& event);virtual const Point& GetExtent();virtual void Load(istream& from);virtual void Save(ostream& to);

78

virtual void Save(ostream& to);private:// ...};

Page 79: Patrones de Diseño

ProxyProxyEjemplo: Un Proxy Virtual

class ImageProxy : public Graphic { // la clase proxyclass ImageProxy : public Graphic { // la clase proxypublic:

ImageProxy(const char* imageFile);virtual ~ImageProxy();i t l id D ( t P i t& t)virtual void Draw(const Point& at);

virtual void HandleMouse(Event& event);virtual const Point& GetExtent();virtual void Load(istream& from);virtual void Load(istream& from);virtual void Save(ostream& to);

protected:Image* GetImage();

i tprivate:Image* _image;Point _extent;char* fileName;c a _ e a e;

};

79

Page 80: Patrones de Diseño

ProxyProxyEjemplo: Un Proxy Virtual

ImageProxy::ImageProxy (const char* fileName) { const Point& ImageProxy::GetExtent () {if ( t t P i t Z ) {

ImageProxy::ImageProxy (const char fileName) {_fileName = strdup(fileName);_extent = Point::Zero; // don't know extent yet_image = 0;

}

if (_extent == Point::Zero) {_extent = GetImage()->GetExtent();

}return _extent;}

Image* ImageProxy::GetImage() {if (_image == 0) {

_image = new Image(_fileName);}

}void ImageProxy::Draw (const Point& at) {

GetImage()->Draw(at);}}

return _image;}

}void ImageProxy::HandleMouse (Event& event) {

GetImage()->HandleMouse(event);}

void ImageProxy::Save (ostream& to) {to << _extent << _fileName;

}}void ImageProxy::Load (istream& from) {

from >> _extent >> _fileName;}

80

}

Page 81: Patrones de Diseño

ProxyProxyEjemplo: Un Proxy Virtual

class TextDocument {public:

TextDocument();void Insert(Graphic*);void Insert(Graphic*);// ...

};

TextDocument* text = new TextDocument;// ...text->Insert(new ImageProxy("anImageFileName"));

81

Page 82: Patrones de Diseño

Ejercicio (Junio de 208)S l li ió d did i t t t iSea la aplicación de pedidos vista en temas anteriores:

Page 83: Patrones de Diseño

EjercicioEjercicio

En el contexto de la aplicación anterior, supónque sólo se puede acceder al disponible de unacuenta de pago si se ha introducido una clave.Utilizando patrones de diseño, implementa enC++ un Proxy de Protección que asegure que seaccede al disponible de la cuenta sólo si la clavees correcta (supón que la clave se pide por laconsola). La clave se almacena en el proxy, yéste recuerda si ya se ha introducidocorrectamente o no.

Page 84: Patrones de Diseño

Solución (1)#include "stdafx.h"#include <iostream>#include <string>using std::cout;using std::cout;using std::string;using std::cin;class Cuenta {{public:

virtual int obtenerDisponible () = 0;};class CuentaReal : public Cuentaclass CuentaReal : public Cuenta{private:

int disponible;public:public:

CuentaReal (int d ) : disponible (d) {}int obtenerDisponible() {return disponible; }

};class ProxyCuenta: public Cuentaclass ProxyCuenta: public Cuenta{private:

CuentaReal * cuenta;string clave;string clave;bool correcta;bool intro;

public:ProxyCuenta ( string psswd CuentaReal & c ) :ProxyCuenta ( string psswd, CuentaReal & c ) :

clave(psswd), cuenta(&c), intro(false), correcta(false) {}int obtenerDisponible();

};

Page 85: Patrones de Diseño

Solución (2)int ProxyCuenta::obtenerDisponible() {if (correcta) return cuenta->obtenerDisponible();else if (!intro) {

intro = true;string cl;cout << "Introduce la clave:\n";cin >> cl;if (cl == clave) {

correcta = true;return cuenta->obtenerDisponible();

}else {

correcta = false;cout << "clave incorrecta\n";return -1;

}}return -1;

}

void main(){

CuentaReal c (100);ProxyCuenta pc ("clave1", c);int d = pc.obtenerDisponible();cout << "Disponible = " << d << "\n";cout << "Disponible = " << pc.obtenerDisponible();

}

Page 86: Patrones de Diseño

AdapterAdapterPropósito.

Convierte el interfaz de una clase en otro que espera el cliente.q pEl adapter permite trabajar juntas a clases que de otra forma no podrían por tener interfaces incompatibles.

También conocido como.También conocido como.Wrapper (envoltorio).

Motivación.A veces una clase de una biblioteca que ha sido diseñada para reutilizarseA veces una clase de una biblioteca que ha sido diseñada para reutilizarse, no puede hacerlo porque su interfaz no coincide con la interfaz específica de dominio que requiere la aplicación.Ej : un editor de dibujo Objetos gráficos con una clase base abstractaEj.: un editor de dibujo. Objetos gráficos, con una clase base abstracta Shape.

Queremos reutilizar una clase existente TextView para implementar TextShape (quizá no tengamos el código fuente de TextView).Solución: Definir una clase TextShape que adapte el interfaz de TextView a Shape. Se puede hacer de dos maneras:

• Adaptador de clase: Heredando el interfaz de Shape y la implementación de

86

• Adaptador de clase: Heredando el interfaz de Shape y la implementación de TextView.

• Adaptador de objeto: Componiendo un objeto TextView dentro de un TextShape, e implementando TextShape en términos de la interfaz de TextView.

Page 87: Patrones de Diseño

AdapterAdapter

Motivación.Adaptador de objeto.p j

87

Page 88: Patrones de Diseño

AdapterAdapter

Estructura.Adaptador de clase.p

88

Page 89: Patrones de Diseño

AdapterAdapter

Estructura.Adaptador de objeto.p j

89

Page 90: Patrones de Diseño

IndiceIndiceIntroducción.Patrones de Creación.Patrones Estructurales.

Patrones de ComportamientoPatrones de Comportamiento.Iterator.Observer.Template Method.State.Strategy.gyCommand.Chain of Responsibility

909090

Chain of Responsibility.Conclusiones.Bibliografía.

Page 91: Patrones de Diseño

Patrones de ComportamientoPatrones de Comportamiento

Tratan sobre algoritmos y la asignación de responsabilidades entre objetos.p jDescriben no sólo patrones de clases y objetos sino patrones de comunicaciónobjetos, sino patrones de comunicación entre ellos.Caracterizan un flujo de control complejo, difícil de seguir en tiempo de ejecución.difícil de seguir en tiempo de ejecución.Permiten que el diseñador se concentre ól ó i t t bj tsólo en cómo interconectar objetos.

Page 92: Patrones de Diseño

IteratorIterator

PropósitoPropósito.Proporciona un medio de acceder a los elementos de un contenedor secuencialmente sin exponer su representación internainterna.

También Conocido Como.Cursor.

Motivación.Un contenedor (p.ej.: una lista) debe proporcionar un medio de navegar sus datos secuencialmente sin exponer su g prepresentación interna.Se debe poder atravesar la lista de varias maneras, dependiendo de lo que se quiera hacer. Probablemente no interesa añadir a la lista operaciones para realizar los diferentes recorridos.Puede necesitarse hacer más de un recorrido simultáneamente.

92Dar la responsabilidad de acceder y recorrer el objeto lista a un objeto Iterator.

Page 93: Patrones de Diseño

IteratorIterator

Motivación.

List ListIterator1 *list

+ Count()+ Append(Element)+ Remove(Element) + First()

+ Next()

- index1 *

+ Next()+ IsDone()+ CurrentItem()

Antes de instanciar el ListIterator, se ha de proporcionar la lista.Una vez que se tiene la instancia, se puede acceder a los elementos de la lista secuencialmenteelementos de la lista secuencialmente.Separar el mecanismo de recorrido del objeto lista, nos permite definir iteradores que implementen distintas estrategias.

93

Page 94: Patrones de Diseño

IteratorIteratorMotivación.

El iterador y la lista están acoplados: el cliente sabe que lo que se está recorriendo es una lista.Es mejor poder cambiar el contenedor sin tener que cambiar el código cliente: iteración polimórfica.

AbstractList+CreateIterator()+ Count()

A d(El t)

Iterator+ First()+ Next()Cli t+ Append(Element)

+ Remove(Element)…

Next()+ IsDone()+ CurrentItem()

Client

1 *list

ListSkipList ListIterator SkipListIterator1skiplist

*

Podemos hacer responsables a las listas de crear sus propios iteradores, mediante un factory

94

method (CreateIterator).Se puede definir algoritmos generales que usan un iterador genérico (en C++: “for_each”, “find_if”, “count”, etc)

Page 95: Patrones de Diseño

IteratorIteratorAplicabilidad. Usar el patrón :

para acceder al contenido de un contenedor sin exponer supara acceder al contenido de un contenedor sin exponer su representación interna.para permitir varios recorridos sobre contenedores.para proporcionar una interfaz uniforme para recorres distintos tipos de contenedores (esto es, permitir la iteración polimórfica).

Estructura. Iterator

Aggregate

+CreateIterator ()

Iterator

+First ()+Next ()+IsDone ()

Client

IsDone ()+CurrentItem ()

ConcreteAggregate

+CreateIterator () ConcreteIterator

95return new ConcreteIterator (this)

Page 96: Patrones de Diseño

IteratorIterator

ParticipantesParticipantes.Iterator.

Define una interfaz para recorrer los elementos y acceder a ellos.ConcreteIterator.

Implementa la interfaz Iterator.Mantiene la posición actual en el recorrido del agregado.

Aggregate.Define una interfaz para crear un objeto Iterator.

ConcreteAggregate.Implementa una interfaz de creación del Iterator para devolver una instancia del ConcreteIterator apropiado.

Colaboraciones.Un ConcreteIterator sabe cuál es el objeto actual del agregado y puede calcular el objeto siguiente del recorrido.

96

Page 97: Patrones de Diseño

IteratorIterator

ConsecuenciasConsecuencias.Permite variaciones en el recorrido de un agregado.Los iteradores simplifican la interfaz del contenedor.Se puede hacer más de un recorrido a la vez sobre un agregado.

Implementación.Implementación.¿Quién controla la iteración?.

El cliente controla la iteración: iterador externo.El iterador controla la iteración: iterador internoEl iterador controla la iteración: iterador interno.

¿Quién define el algoritmo de recorrido?El iterador.El d l it d ól l l t d d lEl agregado, y el iterador sólo almacena el estado de la iteración. A este tipo de iterador se le llama cursor.

¿Cómo de robusto es el iterador?Iterador robusto: Las inserciones y borrados no interfieren en el

97

Iterador robusto: Las inserciones y borrados no interfieren en el recorrido (y se hace sin copiar el agregado).

Page 98: Patrones de Diseño

IteratorIterator

I l t ióImplementación.Operaciones adicionales del iterador.

Por ejemplo, iteradores ordenados podrían tener una operaciónPor ejemplo, iteradores ordenados podrían tener una operación Previous. Otras como SkipTo.

Usar iteradores polimórficos en C++.Los iteradores polimórficos han de crearse dinámicamente por unLos iteradores polimórficos han de crearse dinámicamente por un método de fabricación.El cliente además es responsable de borrarlos (propenso a errores)errores).

Iteradores para Composites.Los iteradores externos pueden ser complicados de implementar

t t ien estructuras recursivas.NullIterators.

Es un iterador degenerado que ayuda a manejar condiciones

98

g q y jlímite.

Page 99: Patrones de Diseño

Iterator

1 Interfaces de la lista y el iterador

IteratorEjemplo

1. Interfaces de la lista y el iterador.template <class Item>class List {public:public:

List(long size = DEFAULT_LIST_CAPACITY);long Count() const;Item& Get(long index) const;// ...

};

template <class Item>template <class Item>class Iterator {public:

virtual void First() = 0;virtual void Next() = 0;virtual bool IsDone() const = 0;virtual Item CurrentItem() const = 0;

protected:

99

protected:Iterator();

};

Page 100: Patrones de Diseño

Iterator

2 Implementaciones de las subclases del iterador

IteratorEjemplo

2. Implementaciones de las subclases del iterador.template <class Item>class ListIterator : public Iterator<Item> {public:public:

ListIterator(const List<Item>* aList) _list(aList), _current(0) {}virtual void First() {_current = 0;}virtual void Next() {_current++;}virtual bool IsDone() const {return _current >= _list->Count(); }virtual Item CurrentItem() const;

private:const List<Item>* list;const List<Item> _list;long _current;

};

template <class Item>template <class Item>Item ListIterator<Item>::CurrentItem () const {

if (IsDone()) throw IteratorOutOfBounds;return _list->Get(_current);

100

}// Se puede implementar un ReverseListIterator, con First // posicionando el iterador al final de la lista, y Next decrementando

Page 101: Patrones de Diseño

Iterator

3 U d l i d

IteratorEjemplo

3. Uso del iterador.void PrintEmployees (Iterator<Employee*>& i) {

for (i.First(); !i.IsDone(); i.Next()) {( (); (); ()) {i.CurrentItem()->Print();

}}

List<Employee*>* employees;// ...ListIterator<Employee*> forward(employees);ReverseListIterator<Employee*> backward(employees);PrintEmployees(forward);PrintEmployees(backward);

101

Page 102: Patrones de Diseño

IteratorIteratorEjemplo4. Evitar ajustarse a una implementación concreta de la lista.j p

Supongamos que tenemos SkipList y SkipListIterator.Se puede introducir un AbstractList para estandarizar la interfaz de la lista (List y SkipList son subclases de AbstractList).( y p )Para permitir iteración polimórfica, AbstractList define un factory method CreateIterator.

template <class Item>template <class Item>class AbstractList {public:virtual Iterator<Item>* CreateIterator() const = 0; //

template <class Item>Iterator<Item>* List<Item>::CreateIterator () const {

return new ListIterator<Item>(this);}// ...

};}

// we know only that we have an AbstractListyAbstractList<Employee*>* employees;// ...Iterator<Employee*>* iterator = employees->CreateIterator();P i tE l (*it t )

102

PrintEmployees(*iterator);delete iterator;

Page 103: Patrones de Diseño

IteratorIteratorEjemplo5. Asegurarse de que los iteradores se borran.g q

Crear un IteratorPtr, que actua de Proxy para un Iterator.Se ocupa de borrar el Iterator cuando se sale de ámbito.

template <class Item>class IteratorPtr {public:

IteratorPtr(Iterator<Item>* i): i(i) { }IteratorPtr(Iterator<Item>* i): _i(i) { }~IteratorPtr() { delete _i; }Iterator<Item>* operator->() { return _i; }Iterator<Item>& operator*() { return *_i; }

AbstractList<Employee*>* employees;// ...I P E l *

p () { _ }private:

// disallow copy and assignment to avoid// multiple deletions of _i:IteratorPtr(const IteratorPtr&);

IteratorPtr<Employee*> iterator(employees->CreateIterator());

PrintEmployees(*iterator);IteratorPtr(const IteratorPtr&);IteratorPtr& operator=(const IteratorPtr&);

private:Iterator<Item>* _i;

103

_};

Page 104: Patrones de Diseño

Iterator

6. Un iterador interno.

IteratorEjemplo

El iterador controla la iteración, y aplica una operación a cada elemento.La operación se puede configurar:

Pasando un puntero a una función o a un objeto funciónPasando un puntero a una función, o a un objeto función.Mediante subclasificación.

template <class Item>class ListTraverser {public:ListTraverser(List<Item>* aList):_iterator(aList) { };

template <class Item>bool ListTraverser<Item>::Traverse () {bool result = false;for ( iterator First(); ! iterator IsDone(); iterator Next()) {

bool Traverse();protected:virtual bool ProcessItem(const Item&) = 0;

private:

for ( _iterator.First(); !_iterator.IsDone();_iterator.Next()) {result = ProcessItem(_iterator.CurrentItem());if (result == false) break;

}return result;

ListIterator<Item> _iterator;};

return result;}

104

Page 105: Patrones de Diseño

Iterator

6 U i d i

IteratorEjemplo

6. Un iterador internoImprimir los n primeros empleados de una lista.

class PrintNEmployees : public ListTraverser<Employee*> {class PrintNEmployees : public ListTraverser<Employee*> {public:

PrintNEmployees(List<Employee*>* aList, int n) :ListTraverser<Employee*>(aList),p y ( )_total(n), _count(0) { }

protected:bool ProcessItem(Employee* const&);

private:private:int _total;int _count;

};}

bool PrintNEmployees::ProcessItem (Employee* const& e) {_count++;e >Print();

105

e->Print();return _count < _total;

}

Page 106: Patrones de Diseño

Iterator

6 U it d i t

IteratorEjemplo

List<Employee*>* employees;

6. Un iterador internoImprimir los n primeros empleados de una lista.

List Employee employees;// ...PrintNEmployees pa(employees, 10);pa.Traverse();

Comparación con un iterador externo:

ListIterator<Employee*> i(employees);int count = 0;int count = 0;for (i.First(); !i.IsDone(); i.Next()) {

count++;i.CurrentItem()->Print();if (count >= 10) break;

}

106

Page 107: Patrones de Diseño

Iterator

6 U i d i

IteratorEjemplo

6. Un iterador internoPueden encapsular distintos tipos de operaciones.

template <class Item>template <class Item>class FilteringListTraverser {public:FilteringListTraverser(List<Item>* aList);

()

template <class Item>void FilteringListTraverser<Item>::Traverse () {bool result = false;for (_iterator.First();!_iterator.IsDone();_iterator.Next()) {

bool Traverse();protected:virtual bool ProcessItem(const Item&) = 0;virtual bool TestItem(const Item&) = 0;

(_ () _ () _ ()) {if (TestItem(_iterator.CurrentItem())) {

result = ProcessItem(_iterator.CurrentItem());if (result == false) break;

}( )private:ListIterator<Item> _iterator;

};

}}return result;

}

107

Page 108: Patrones de Diseño

ObserverObserver

P ó itPropósito.Define una dependencia de uno-a-muchos entre objetos, de forma que cuando un objeto cambie de estado se notifique y q j q yactualicen automáticamente todos los objetos que dependen de él.

También conocido comoTambién conocido como.Dependents, Publish-Subscribe

Motivación.Mantener consistencia entre objetos relacionados.No queremos obtener dicha consistencia aumentando el acoplamiento entre clasesacoplamiento entre clases.Ej.: separación de la presentación en GUI de los datos de aplicación subyacente.

108

Page 109: Patrones de Diseño

ObserverObserver

Motivación.

40

A

C

D

10

20

30

40

A B C DX 60 20 15 5Y 40 25 15 20

B 0A B C D

Y 40 25 15 20Z 10 10 20 60

ModeloA: 40%B: 25%C 15%

109

C: 15%D: 20%

Page 110: Patrones de Diseño

ObserverObserverAplicabilidad.

Cuando una abstracción tiene dos aspectos y uno depende del otro.Cuando un cambio en un objeto requiere cambiar otros, y no sabemos cuántos hay que cambiar.y qCuando un objeto debería ser capaz de notificar a otros sin hacer suposiciones sobre quiénes son dichos objetos (esto es, no queremos que los objetos estén fuertemente acoplados)que los objetos estén fuertemente acoplados).

Estructura.Subject Observerobservers

1 *0 1+Attach (Observer)+Detach (Observer)+Notify ()

+Update()forall o in observers

o.Update()

1..*0..1

o.Update()

ConcreteSubject

ConcreteObserver- observerState

subject0..1

110+GetState ()+SetState ()

- subjectState +Update ()subject

return subjectState observerState=subject->GetState()

Page 111: Patrones de Diseño

ObserverObserverParticipantes.

S bj tSubject.Conoce a sus observadores, que pueden ser un número arbitrario.Proporciona un interfaz para añadir y quitar objetos Observer.

ObObserver.Define un interfaz de actualización para los objetos que deben ser notificados sobre cambios en un sujeto.

ConcreteSubjectConcreteSubject.Almacena estado de interés para ConcreteObservers.Manda notificaciones a sus observadores cuando su estado cambia.

ConcreteObserverConcreteObserver.Mantiene una referencia a objetos ConcreteSubject.Almacena el estado que debe ser consistente con el del sujeto.Implementa el interfaz de actualización del Observer para mantener suImplementa el interfaz de actualización del Observer para mantener su estado consistente con el del sujeto.

111

Page 112: Patrones de Diseño

ObserverObserverColaboraciones.

El ConcreteSubject notifica a sus observadores cada vez que se produce un cambio que pudiera hacer que el estado de estos fuese inconsistente con el suyo.yDespués de ser notificado del cambio, un ConcreteObserver puede pedir al subject más información.

:ConcreteSubject barDiagram:ConcreteObserver

sectorDiagram:ConcreteObserver

SetState()Notify()

Update()

GetState()GetState()

Update()GetState()

112

Page 113: Patrones de Diseño

ObserverObserver

ConsecuenciasConsecuencias.Permite modificar los sujetos y observadores de maneraindependiente.S d tili l j t i b dSe pueden reutilizar los sujetos sin sus observadores yviceversa.Se pueden añadir observadores sin modificar el sujeto u otrosobservadoresobservadores.Acoplamiento abstracto entre sujeto y observador. El sujeto noconoce la clase concreta de ningún observador (el acoplamientoes mínimo)es mínimo).Capacidad de comunicación mediante difusión. La notificacióndel sujeto se envía automáticamente a todos los observadoressuscritos. Se pueden añadir y quitar observadores en cualquierp y q qmomento.Actualizaciones inesperadas. Una operación aparentementeinofensiva sobre el sujeto puede desencadenar una cascada de

bi l b d113

cambios en los observadores.

Page 114: Patrones de Diseño

ObserverObserver

ImplementaciónImplementación.Correspondencia entre sujetos y observadores.

Que el sujeto guarde referencias a los observadores a los que debe notificarnotificar.

Observar más de un sujeto.Ej.: una hoja de cálculo puede observar más de un origen de datos.Extender la interfaz de actualización para que el observador sepaExtender la interfaz de actualización para que el observador sepa qué sujeto se ha actualizado (quizá simplemente el sujeto se pase a sí mismo como parámetro del update()).

¿Quién dispara la actualización?¿Q pLas operaciones que cambien el estado del sujeto llaman a Notify().

• Ventaja: los clientes no tienen que hacer nada.• Inconveniente: no es óptimo si hay varios cambios de estado seguidos.

Los clientes llaman a Notify():• Ventaja: se puede optimizar llamando a notify sólo después de varios

cambios.• Inconveniente: los clientes tienen la responsabilidad añadida de llamar

114

Inconveniente: los clientes tienen la responsabilidad añadida de llamar a Notify().

Page 115: Patrones de Diseño

ObserverObserver

Implementación.Referencias perdidas a sujetos borrados.

Una manera de evitarlo es notificar a los observadores cuando se borra un sujeto.

Asegurarse de que el estado del Sujeto sea consistenteAsegurarse de que el estado del Sujeto sea consistente consigo mismo antes de la notificación:

Hay que tener cuidado con las operaciones heredadas.Hay que tener cuidado con las operaciones heredadas.

void MySubject::Operation (int newValue) {BaseClassSubject::Operation(newValue);BaseClassSubject::Operation(newValue);// trigger notification_myInstVar += newValue;// update subclass state (too late!)

}115

}

Page 116: Patrones de Diseño

ObserverObserver

ImplementaciónImplementación.Evitar protocolos específicos del obervador: los modelos push y pull.

Las implementaciones de observer suelen hacer que el sujeto envie información adicional como parámetro de Update().Dos extremos:

• Modelo Push: el sujeto envía información detalla del cambio quieran• Modelo Push: el sujeto envía información detalla del cambio, quieran los observadores o no.

Inconveniente: observadores menos reutilizables.• Modelo Pull: el sujeto no envía nada, y los observadores piden

d é l d t ll lí it tdespués los detalles explícitamente.Inconveniente: puede ser poco eficiente.

Especificar las modificaciones de interés explícitamente:Mejorar la eficiencia haciendo que los observadores registrenMejorar la eficiencia haciendo que los observadores registren solo aquellos eventos que les interesen.Los observadores se subscriben a aspectos del sujeto.

116

Page 117: Patrones de Diseño

ObserverObserverImplementación.

Encapsular la semántica de las operaciones complejasEncapsular la semántica de las operaciones complejas.Si la relación de dependencia entre sujetos y observadores es compleja, puede ser necesario un objeto intermedio para la gestión de cambios (ChangeManager).Minimizar el trabajo necesario para que los observadores reflejen los cambios en el j p q jsujeto.Ej.: si varios sujetos han de cambiarse, asegurarse de que se notifique a los observadores sólo después del cambio en el último sujeto.

Subject

+Attach (Observer o)

Observer

+Update(Subject)

subjects

1..*0..*ChangeManagerchman

1Subject-Observer mapping

observers

+Attach (Observer o)+Detach (Observer)+Notify ()

+Update(Subject)+Register (Subject,Observer)+Unregister (Subject,Observer)+Notify ()

chman->Notify()

Marcar todos los observersa actualizar.Actualizar los observerschman >Notify()

chman->Registar(this,o)SimpleChangeManager DAGChangeManager

Actualizar los observers marcados.

117

+Register (Subject,Observer)+Unregister (Subject,Observer)+Notify ()

+Register (Subject,Observer)+Unregister (Subject,Observer)+Notify ()

forall s in subjects:forall o in observers:

o->Update(s)

Page 118: Patrones de Diseño

ObserverObserverEjemplo

class Subject;

class Subject {public:

virtual ~Subject();class Subject;class Observer {public:

virtual ~ Observer();

j ()virtual void Attach(Observer*);virtual void Detach(Observer*);virtual void Notify();

protected:()virtual void Update (Subject*

theChangedSubject) = 0;// soporte de múltiples subjects

protected:

protected:Subject();

private:List<Observer*> *_observers;protected:

Observer();};

_};void Subject::Attach (Observer* o) {

_observers->Append(o);}}void Subject::Detach (Observer* o) {

_observers->Remove(o);}void Subject::Notify () {

ListIterator<Observer*> i(_observers);for (i.First(); !i.IsDone(); i.Next()) {

i CurrentItem() >Update(this);

118

i.CurrentItem()->Update(this);}

}

Page 119: Patrones de Diseño

ObserverObserverEjemplo

class ClockTimer : public Subject { class DigitalClock: public Widget, publicclass ClockTimer : public Subject {// Concrete subjectpublic:

ClockTimer();

class DigitalClock: public Widget, public Observer {public:

DigitalClock(ClockTimer*);i t l Di it lCl k()

()virtual int GetHour();virtual int GetMinute();virtual int GetSecond();void Tick();

virtual ~DigitalClock();virtual void Update(Subject*);// overrides Observer operationvirtual void Draw();void Tick();

};

void ClockTimer::Tick () {

virtual void Draw();// overrides Widget operation;// defines how to draw the digital clock

private:Cl kTi * bj t// update internal time-keeping state

// ...Notify();}

ClockTimer* _subject;};

DigitalClock::DigitalClock (ClockTimer* s) {bj t} _subject = s;

_subject->Attach(this);}DigitalClock::~DigitalClock () {

119

DigitalClock:: DigitalClock () {_subject->Detach(this);

}

Page 120: Patrones de Diseño

ObserverObserverEjemplo

void DigitalClock::Update (Subject* theChangedSubject) {if (theChangedSubject == _subject) Draw();

}void DigitalClock::Draw () {void DigitalClock::Draw () {

int hour = _subject->GetHour(); // get the new values from the subject

int minute = _subject->GetMinute();// etc.// draw the digital clock

}class AnalogClock : public Widget public Observer {class AnalogClock : public Widget, public Observer {public:

AnalogClock(ClockTimer*);virtual void Update(Subject*);virtual void Draw();// ...

};

120

ClockTimer* timer = new ClockTimer;AnalogClock* analogClock = new AnalogClock(timer);DigitalClock* digitalClock = new DigitalClock(timer);

Page 121: Patrones de Diseño

Observer

Sistemas de eventos en Java (observer listener)

ObserverUsos Conocidos

Sistemas de eventos en Java (observer=listener)AWT/SwingJavabeans

MVC en el sistema de ventanas de SmalltalkModel=SubjectView=ObserverView=ObserverController=Cualquier objeto que cambie el estado de Subject

MVC en entornos web (J2EE)Model=EJBView=JSPController=servletController servlet

121

Page 122: Patrones de Diseño

Template MethodTemplate MethodPropósito.p

Definir el esqueleto de un algoritmo, delegando en las subclasesalguno de sus pasos.Permite que las subclases cambien pasos de un algoritmo sin cambiarPermite que las subclases cambien pasos de un algoritmo sin cambiarsu estructura.

Motivación.Ej.: MFCs, abrir un fichero.

Document Applicationdocs1 *

void Application::OpenDocument (const char* name) {if (!CanOpenDocument(name)) {

// cannot handle this document

+Abrir()+Cerrar()+Guardar()

D R d()

pp

+AddDocument()+OpenDocument()+DoCreateDocument()+CanOpenDocument()

1..* // cannot handle this documentreturn;

}Document* doc = DoCreateDocument();if (doc) {+DoRead() +CanOpenDocument()

+AboutToOpenDocument()

MyDocument MyApplication

if (doc) {_docs->AddDocument(doc);AboutToOpenDocument(doc);doc->Open();doc >DoRead();

122

y

+DoCreateDocument()+CanOpenDocument()+AboutToOpenDocument()

+DoRead()

return MyDocument

doc->DoRead();}

}

Page 123: Patrones de Diseño

Template MethodAplicabilidad.

Template Method

Para implementar las partes de un algoritmo que no cambian, y dejar que las subclases implementen el comportamiento que puede variarque puede variar.Cuando el comportamiento repetido de varias subclases debería factorizarse y localizarse en una clase común, para evitar código duplicado.Para controlar las extensiones de las subclases.

E t tEstructura. ClaseAbstracta

+TemplateMethod()+PrimitiveOperation1() …+PrimitiveOperation2()+…

…PrimitiveOperation1()…PrimitiveOperation2()

123

ConcreteClass+PrimitiveOperation1()+PrimitiveOperation2()

Page 124: Patrones de Diseño

StateStatePropósito.

Permitir que un objeto modifique su comportamiento cada vez que cambie suPermitir que un objeto modifique su comportamiento cada vez que cambie su estado interno. Parecerá que cambia la clase del objeto.

También conocido como.Objets for state (estados como objetos).

Motivación.TCPConnection para representar una conexión de red.p pPuede estar en distintos estados: establecida, escuchando y cerrada.El efecto de cada petición sobre cada objeto depende del estado en el que está.

124

Page 125: Patrones de Diseño

StateState

Estructura.

125

Page 126: Patrones de Diseño

StrategyStrategyPropósito.

Define una familia de algoritmos, encapsula cada uno de ellos, y los hace intercambiables.Permite que un algoritmo varíe independientemente de los clientes que los usan.

También conocido como.Policy (política).

MotivaciónMotivación.Ej.: Algoritmos para dividir en líneas un flujo de texto.Clases que encapsulen los distintos algoritmos de división. Un algoritmo así encapsulado se denomina estrategiaencapsulado se denomina estrategia.

126

Page 127: Patrones de Diseño

StrategyStrategy

Estructura.

127

Page 128: Patrones de Diseño

CommandCommandPropósito.

Encapsula peticiones a objetosEncapsula peticiones a objetos.Permite parametrizar a los clientes con diferentes peticiones, hacer cola o llevar un registro de peticiones, así como deshacer las peticionespeticiones.

También conocido como.Action, Transaction.

M ti ióMotivación.Framework gráfico tipo MFC. Peticiones de los distintos widgets encapsuladas como objetos.

128

Page 129: Patrones de Diseño

CommandCommand

M ti ióMotivación.

129

Page 130: Patrones de Diseño

CommandCommand

E t tEstructura.

130

Page 131: Patrones de Diseño

Chain of ResposibilityChain of ResposibilityPropósito.

Evita acoplar el emisor de una petición a su receptor, dando a más de un objeto la posibilidad de responder a la petición.Encadena los objetos receptores y pasa la petición a través de laEncadena los objetos receptores y pasa la petición a través de la cadena hasta que es procesada por algún objeto.

Motivación.Ej.: ayuda sensible al contexto en una GUI.Si no existe ayuda para una parte de la interfaz, se muestra ayuda para una parte más general.p p g

131

Page 132: Patrones de Diseño

Chain of ResposibilityChain of Resposibility

Motivación.

132

Page 133: Patrones de Diseño

Chain of ResposibilityChain of Resposibility

Estructura.

133

Page 134: Patrones de Diseño

IndiceIndice

I t d ióIntroducción.Patrones de Creación.Patrones EstructuralesPatrones Estructurales.Patrones de Comportamiento.

ConclusionesConclusiones.Bibliografía.

134134134

Page 135: Patrones de Diseño

ConclusionesConclusiones

Los patrones de diseño capturan el conocimiento queLos patrones de diseño capturan el conocimiento quetienen los expertos a la hora de diseñar.

Los patrones ayudan a generar software “maleable”(software que soporta y facilita el cambio, la reutilizacióny la mejora)y la mejora).

Los patrones de diseño son guías, no reglas rigurosas.

Cada patrón describe la solución a problemas que serepiten una y orta vez en nuestro entorno de forma querepiten una y orta vez en nuestro entorno, de forma quese puede usar esa solución todas las veces que hagafalta.

135

Page 136: Patrones de Diseño

IndiceIndice

I t d ióIntroducción.Patrones de Creación.Patrones EstructuralesPatrones Estructurales.Patrones de Comportamiento.ConclusionesConclusiones.

Bibliografía.

136136136

Page 137: Patrones de Diseño

BibliografíaBibliografía

“D i tt l t f bl bj t“Design patterns, elements of reusable object-oriented software”. Gamma, Helm, Jonhnson, Vlissides Addison Wesley 1995 (traducido alVlissides. Addison Wesley, 1995 (traducido al español en 2003).

“Applying UML and Patterns. An introduction to Object Oriented Analysis and Design andObject-Oriented Analysis and Design and Iterative Development. 3rd Edition.” Craig Larman Prentice Hall 2005Larman. Prentice Hall.2005.

http://hillside net/137137137

http://hillside.net/