COSC 3351 Software Design Design Patterns Creational...
Transcript of COSC 3351 Software Design Design Patterns Creational...
1
Edgar Gabriel
COSC 3351
Software Design
Design Patterns
Creational Patterns
Edgar Gabriel
Spring 2008
COSC 3351 – Software Design
Edgar Gabriel
Object Oriented Software Design
• Determine right granularity of objects
• Define class interfaces and inheritance hierarchies
• Establish key relationships
• Design should be specific to solve a problem
• …but general enough to be reusable
• Experienced designer do not solve every problem from
scratch
– Reuse solutions that worked in the past
– Leads to recurring patterns in many programs
2
COSC 3351 – Software Design
Edgar Gabriel
Design patterns
• A design pattern is a way of reusing abstract knowledge about a problem and its solution– Patterns are devices that allow programs to share knowledge about
their design
• A pattern is a description of the problem and the essence of its solution– Documenting patterns is one way to reuse and share the
information about how it is best to solve a specific design problem
• A pattern should be sufficiently abstract to be reused in different settings
• Patterns often rely on object characteristics such as inheritance and polymorphism
COSC 3351 – Software Design
Edgar Gabriel
History of Design Patterns
• Architect Christopher Alexander
– A Pattern Language (1977)
– A Timeless Way of Building (1979)
• “Gang of four”
• Erich Gamma
• Richard Helm
• Ralph Johnson
• John Vlissides
– Design Patterns: Elements of Reusable Object-
Oriented Software (1995)
• Many since
• Conferences, symposia, books
3
COSC 3351 – Software Design
Edgar Gabriel
Pattern elements
• Name
– A meaningful pattern identifier
• Problem description
• Solution description
– Not a concrete design but a template for a design solution that can be instantiated in different ways
• Consequences
– The results and trade-offs of applying the pattern
COSC 3351 – Software Design
Edgar Gabriel
Abstraction Levels
Patterns exist on different abstraction levels:
• basic building blocks (algorithms and components), provided by
language or by libraries
• e.g. hash tables, linked lists, sort algorithms, math
• e.g. inheritance and polymorphism, encapsulation
• design patterns: general design problems in particular context
concerning several classes
• e.g.GOF-design patterns
• architecture patterns: architecture decisions concerning the
whole system (or subsystem)
• Architectural styles discussed previously
4
COSC 3351 – Software Design
Edgar Gabriel
Classifying design patterns
• Purpose:
– Creational: concern the process of object creation
– Structural: composition of classes or objects
– Behavioral: characterize ways in which objects interact and distribute responsibility
• Scope:
– Class patterns: deal with relationships between classes and subclasses, i.e. inheritance
• Static, compile time
– Object patterns: can be changed at runtime, dynamically
COSC 3351 – Software Design
Edgar Gabriel
Purpose
Creational Structural Behavioral
Scope Class Factory Method Adaptor(class) Interpreter
Template Method
Object Abstract Factory Adaptor(object) Chain of
Responsibility
Builder Bridge Command
Prototype Composite Iterator
Singleton Decorator Mediator
Façade Observer
Flyweight State
Proxy Strategy
Visitor
Memento
5
COSC 3351 – Software Design
Edgar Gabriel
Specifying Object Interfaces
• An operation declared by an object specifies
– Operation name
– Objects taken as parameter
– Return value
-> operation signature
• Set of signatures defines the interface of an object
• An interface does not say anything about the
implementation
– Different objects having the same interface
– Association of the request to an object at runtime known as dynamic binding
COSC 3351 – Software Design
Edgar Gabriel
Specifying Object Interfaces
• Class vs. Interface inheritance
– Class inheritance defines an objects implementation in terms of another objects implementation
• Mechanism for code reuse
– Interface inheritance defines describes when an object can be used in place of another
• Subtyping
• In C++: inherit publicly from a class that has (pure) virtual functions
6
COSC 3351 – Software Design
Edgar Gabriel
Putting Reuse Mechanisms to Work
• Class Inheritance
– Reuse by subclassing
– White box reuse: internals of parents class often visible to subclasses
– Defined statically at compile time
• Composition
– Assembling objects in order to create more complex objects
– Black-box reuse: no internal details of objects visible
COSC 3351 – Software Design
Edgar Gabriel
Putting Reuse Mechanisms to Work (II)
• Parameterized types
– Often called generics or templates
– Define a type without specifying the types it uses
– Static, compile time procedure
• Delegation:
– Two objects involved in handling a request
• A receiving object delegates the operation to the delegate
• Instead of the subclass being a ‘superclass’ the subclass would have a ‘superclass’ object
7
COSC 3351 – Software Design
Edgar Gabriel
Delegation example
13
class I {
public:
virtual void f() = 0;
virtual void g() = 0;
} class A : public I {
public:
void f() { cout << "A: doing f()" << endl; }
void g() { cout << "A: doing g()" << endl; }
}
class C : public I {
public:
C() : i( new A() ) { }
virtual ~C() { delete i; }
void f() { i->f(); }
void g() { i->g(); }
}
int main() {
C* c = new C();
c->f();
c->g();
}
COSC 3351 – Software Design
Edgar Gabriel
An example: a maze game
Maze
+ AddRoom()
+RoomNo()
Room
+ Enter()
+ SetSide()
+ GetSide()
- RoomNo
Wall
+ Enter()
Door
+ Enter()
- isOpen
<<interface>>
MapSite
+ Enter()
8
COSC 3351 – Software Design
Edgar Gabriel
15
class MapSite {
public:
virtual void Enter() = 0;
}; class Room : public MapSite {
public:
Room (int RoomNo);
MapSite * GetSide(Direction) const;
void SetSide (Direction, MapSite*);
virtual void Enter();
private:
MapSite *_sides[4];
int _RoomNo;
}
class Wall : public MapSite {
public:
Wall();
}
class Door: public MapSite {
public:
Door (Room *=0, Room*=0 );
virtual void Enter();
Room * OtherSideFrom (Room *);
private:
Room *_room1, *_room2;
bool _isOpen;
}
COSC 3351 – Software Design
Edgar Gabriel
16
// This class represents a collection of rooms
class Maze {
public:
Maze();
void AddRoom (Romm *);
Room* RoomNo(int) const;
}; // The class MazeGame creates a Maze
Maze * MazeGame:: CreateMaze {
Maze* aMaze = new Maze;
Room* r1 = new Room( 1 );
Room* r2 = new Room( 2 );
Door* theDoor = new Door( r1, r2);
aMaze->addRoom( r1 );
aMaze->addRoom( r2 );
r1->setSide( North, new Wall );
r1->setSide( East, theDoor );
r1->setSide( South, new Wall );
r1->setSide( West, new Wall );
r2->setSide( North, new Wall );
r2->setSide( East, new Wall );
r2->setSide( South, new Wall );
r2->setSide( West, theDoor );
return aMaze;
}
9
COSC 3351 – Software Design
Edgar Gabriel
Problem with previous code
• Contains the explicit types of Room, Door etc.
– Difficult to reuse the room layout described by CreateMaze for other type of Doors, Walls etc.
class BombedMazeGame : public MazeGame {
public:
Maze* CreateMaze() {
Maze* aMaze = new Maze;
Room* r1 = new RoomWithABomb( 1 );
Room* r2 = new RoomWithABomb( 2 );
Door* theDoor = new Door( r1, r2);
aMaze->addRoom( r1 );
aMaze->addRoom( r2 );
r1->setSide( North, new BombedWall);
r1->setSide( East, theDoor );
…
COSC 3351 – Software Design
Edgar Gabriel
Abstract Factory
• Intent: Provide an interface for creating families of
related or dependent objects without specifying their
concrete classes
• Applicability: Use the Abstract Factory Pattern when
– A system should be independent of how its products are created, composed and represented
– A system should be configured with one of multiple families of products
– A family of related product objects is designed to be
used together, and you need to enforce this constraint
– You want to provide a class library of products, and you want to reveal just the interfaces, not their implementation
10
COSC 3351 – Software Design
Edgar Gabriel
Abstract Factory (II)
class MazeFactory {
public:
MazeFactory() {
virtual 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
{ return new Door ( r1, r2 ); }
}
Maze *MazeGame::CreateMaze (MazeFactory& factory ) {
Maze* aMaze = factory.MakeMaze();
Room* r1 = factory.MakeRoom(1);
Room* r2 = factory.MakeRoom(2);
Door* aDoor = factory.MakeDoor ( r1, r2);
…
r1->SetSide(North, factory.MakeWall() );
…
COSC 3351 – Software Design
Edgar Gabriel
Abstract Factory (III)
MazeGame game;
EnchantedMazeFactory factory;
game.CreateMaze(factory);
…
class EnchantedMazeFactory : public MazeFactory
public:
EnchantedMazeFactory();
virtual Room* MakeRoom(int n) const
{ return new EnchantedRoom (n ); }
virtual Door *MakeDoor(Room* r1, Room* r2 ) const
{ return new EnchantedDoor( r1, r2); }
…
11
COSC 3351 – Software Design
Edgar Gabriel
Abstract Factory (IV)
AbstractFactory
CreateProductA()
CreateProductB()
ConcreteFactory1
Client
ProductA1ProductA2
AbstractProductA
ProductB2 ProductB1
AbstractProductB
ConcreteFactory2
CreateProductA()
CreateProductB()
COSC 3351 – Software Design
Edgar Gabriel
Abstract Factory (V)
• Participants:
– Abstract Factory: declares an interfaces for operations that create abstract product objects
– ConcreteFactory: implements the operations to create concrete product objects
– AbstractProduct: declares an interface for a type of product object
– ConcreteProduct: defines a product to be created by corresponding concrete factory; implements the AbstractProduct interface
– Client: uses only interfaces declared by AbstractFactoryand AbstractProduct
12
COSC 3351 – Software Design
Edgar Gabriel
AbstractFactory (VI)
• Collaborations
– Normally, a single instance of a Concrete Factory is created at run time (see Singleton pattern later in the course)
– The ConcreteFactory creates products having a particular implementation
– To create different product objects, clients should use different concrete Factories
– AbstractFactory defers creation of product objects to its ConcreteFactory subclasses
• Downside:
– Factory classes parallels the class hierarchies of the products
COSC 3351 – Software Design
Edgar Gabriel
Another example
• Widget toolkit
– Different look and feel, e.g. for Unix & Windows
– Family of widgets: Scroll bars, buttons, dialogs…
– Want to allow changing look & feel
– Most parts of the system need not know what look & feel is used
– Creation of widget objects should not be distributed
13
COSC 3351 – Software Design
Edgar Gabriel
Factory Method
• Intent: define an interface for creating an object, but
let subclasses decide which class to instantiate. Factory
Method lets a class defer instantiation to subclasses
• Applicability: Use the Factory Method pattern when
– A class can’t anticipate the class of objects it must create
– A class wants its subclasses to specify the objects it creates
– Classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate
COSC 3351 – Software Design
Edgar Gabriel
Factory Method(II)
class MazeGame {
public:
Maze* CreateMaze() {
virtual 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
{ return new Door ( r1, r2 ); }
}
Maze *MazeGame::CreateMaze () {
Maze* aMaze = MakeMaze();
Room* r1 = MakeRoom(1);
Room* r2 = MakeRoom(2);
Door* aDoor = MakeDoor ( r1, r2);
…
r1->SetSide(North, MakeWall() );
…
14
COSC 3351 – Software Design
Edgar Gabriel
Formal Model
ConcreteProduct
<<interface>>
ConcreteProduct
ConcreteCreator
<<interface>>
Creator
+FactoryMethod()
+AnOperation()
+FactoryMethod()
product = FactoryMethod();
return new ConcreteProduct;
COSC 3351 – Software Design
Edgar Gabriel
Factory Method
• Participants:
– Product : defines the interface of objects the factory method creates
– ConcreteProduct: implements the Product interface
– Creator: declares the factory method, which returns an object of type Product.
• May also define a default implementation of the factory method that returns a default ConcreteProduct object.
– ConcreteCreator: overrides the factory method to return an instance of a ConcreteProduct
15
COSC 3351 – Software Design
Edgar Gabriel
• Factory Method vs. Abstract Factory:
– Creates one object, not families of object.
– Works at the routine level, not class level.
– Helps a class perform an operation, which requires creating an object.
– Abstract Factory classes are often implemented using Factory Methods
COSC 3351 – Software Design
Edgar Gabriel
Parameterized Factory Methods
• Parameterized factory methods lets the factory method
create multiple kinds of products
class Creator{
public:
virtual Product* Create(ProductID);
}
Product* Creator :: Create(ProductID id) {
if (id==FIRST_OPTION ) return new FirstProduct;
if (id==SECOND_OPTION) return new SecondProduct;
}
16
COSC 3351 – Software Design
Edgar Gabriel
Parameterized Factory Methods (II)
• If another class wants to override the Create method of
the base class
Product *MyCreator:: Create ( ProductId id ) {
if (id==THIRD_PRODUCT) return ThirdProduct;
// fall back to the Create Method of the base class
// if options do not match
return Createor::Create(id);
}
COSC 3351 – Software Design
Edgar Gabriel
Using templates to avoid subclassing
• C++ templates avoid generating subclasses just to
create the appropriate product objects
class Creator{
public:
virtual Product* Create(ProductID)=0;
}
template <class TheProduct>
Class StandardCreator: public Creator {
public: virtual Product *CreateProduct();
}
template <class TheProduct>
Product* StandardCreator<TheProduct> :: CreateProduct() {
return new TheProduct;
}
17
COSC 3351 – Software Design
Edgar Gabriel
Builder
• Intent: separate the construction of a complex object
from its representation such that the same construction
process can create different representations
• Applicability: Use the builder pattern when
– The algorithm for creating a complex object should be independent of the parts that make up the object and how they are assembled
– The construction process must allow different representations for the object that’s constructed
COSC 3351 – Software Design
Edgar Gabriel
class MazeBuilder {
public:
virtual void BuildMaze(){}
virtual void BuildRoom (int room ) {}
virtual void BuildDoor ( int room1, int room2 ) {}
virtual Maze* GetMaze() {return 0; }
}
Maze *MazeGame::CreateMaze (MazeBuilder& builder) {
builder.BuildMaze();
builder.BuildRoom(1);
builder.BuildRoom(2);
builder.BuildDoor ( r1, r2);
// Note that the walls are creating internally
return builder.GetMaze();
}
18
COSC 3351 – Software Design
Edgar Gabriel
class StandardMazeBuilder: public MazeBuilder {
public:
virtual void BuildMaze();
virtual void BuildRoom (int room );
virtual void BuildDoor ( int room1, int room2 );
virtual Maze* GetMaze();
private:
Direction CommonWall ( Room*, Room* );
Maze* _currentMaze;
}
void StandardMazeBuilder:: BuildMaze () {
_currenMaze = new Maze;
}
void StandardMazeBuilder:: BuildRoom(int n) {
Room* room = new Room(n);
_currentMaze->AddRoom (room);
room->SetSide(North, new Wall );
room->SetSide(South, new Wall );
room->SetSide(East, new Wall );
room->SetSide(West, new Wall );
}
COSC 3351 – Software Design
Edgar Gabriel
Maze *maze;
MazeGame game;
StandardMazeBuilder builder;
maze = game.CreateMaze (builder);
Builder
• Difference between Abstract Factory and Builder
– Builder pattern focuses on constructing a complex object step by step
– Abstract Factory emphasis is on a family of product objects
– E.g. CreateMaze does not have anywhere the notion, that you are dealing with objects of type Room or Door.
19
COSC 3351 – Software Design
Edgar Gabriel
Formal Model
Director
ConcreteBuilder
<<interface>>
Builder
+BuildPart()
+BuildPart()
for all objects in structure{
builder->BuildPart();
}
Construct()
Product
COSC 3351 – Software Design
Edgar Gabriel
Builder• Participants:
– Builder: specifies an abstract interface for creating parts of a Product object
– Concrete Builder:
• constructs and assembles parts of the product by implementing the BuilderInterface
• Defines and keeps track of the representations it creates
• Provides an interface for retrieving the product
– Director: constructs an object using the Builder Interface
– Product:
• represents the complex object under construction
• define the process by which it is assembled.
20
COSC 3351 – Software Design
Edgar Gabriel
Builder
• Why no abstract class for the products?
– In the common case, the products produced by the concrete builder differ so greatly in their representation that there is little gain from giving different products a common parent class
COSC 3351 – Software Design
Edgar Gabriel
Another exampleclass CountingMazeBuilder: public MazeBuilder {
public:
virtual void BuildMaze();
virtual void BuildRoom (int room );
virtual void BuildDoor ( int room1, int room2 );
virtual Maze* GetMaze();
private:
int _doors, _rooms;
}
CoutingMazeBuilder:: CountingMazeBuilder () {
_rooms = _doors = 0;
}
void CountingMazeBuilder:: BuildRoom (int) {
_rooms++;
}
void CountingMazeBuilder:: BuildDoor(int, int ) {
_doors++;
}
21
COSC 3351 – Software Design
Edgar Gabriel
Prototype
• Intent: Specify the kinds of objects to create using a
prototypical instance and create new objects by
copying this prototype
• Applicability: use the prototype patterns when a system
should be independent of how its products are created,
composed and represented, and
– When the classes to instantiate are specified at runtime
– To avoid building a class hierarchy of factories which parallels the class hierarchy of products
– When instances of a class can have one of only a few different combinations
COSC 3351 – Software Design
Edgar Gabriel
Extending the MazeFactory using Prototypes
class MazePrototypeFactory: public MazeFactory {
public:
MazePrototypeFactory (Maze*, Wall*, Room*, Door*);
virtual Maze* MakeMaze() const;
virtual Room* MakeRoom(int) const;
virtual Wall* MakeWall() const;
virtual Door* MakeDoor(int, int) const;
private:
Maze* _prototypeMaze;
Room* _prototypeRoom;
Wall* _prototypeWall;
Door* _protytypeDoor;
};
MazePrototypeFactory :: MazePrototypeFactory ( Maze* m,
Wall *w, Room *r, Door *d ) {
_prototypeMaze = m;
_prototypeWall = w;
_prototypeRoom = r;
_prototypeDoor = d;
}
22
COSC 3351 – Software Design
Edgar Gabriel
Member functions
Wall* MazePrototypeFactory::MakeWall () const {
return _prototypeWall->Clone;
}
Door *MazePrototypeFactory::MakeDoor (Room *r1,Room* r2 ){
Door *door = _prototypeDoor->Clone();
door->Initialize ( r1, r2 );
return door;
}
• To change the type of maze to be used, just initialize
MazePrototypeFactory with a different set of
prototypes
MazePrototypeFactory bombedMazeFactory (
new Maze, new BombedWall,
new RoomWithABomb, new Door
};
COSC 3351 – Software Design
Edgar Gabriel
Prototype
• An object that can be used as a prototype
– must support the Clone operation
– Might need an Initialize operation for reinitializing the internal state
• Prototype reduces subclassing, since it does not require
a creator class such as abstract factory
23
COSC 3351 – Software Design
Edgar Gabriel
Shallo vs. Deep Copy
Original object
Shallow copy Deep copy
Images taken from: http://www.eli.sdsu.edu/courses/spring98/cs635/notes/creational/creational.html
COSC 3351 – Software Design
Edgar Gabriel
Prototype pattern
• Popular approach:
– Create a prototype of the composite object
– Insert it into a prototype pool/list and reuse it whenever necessary
• Also often used with Abstract Factory
– E.g. an abstract factory stores a set of prototypes from which to clone and return product objects
24
COSC 3351 – Software Design
Edgar Gabriel
Singleton
• Intent: ensure a class only has one instance, and
provide a global point of access to it.
• Applicability: use the singleton pattern when
– There must be exactly one instance of a class, and it must be accessible to clients from a well known access point
– When the sole instance should be extensible by subclassing and clients should be able to use an extended instance without modifying their code.
COSC 3351 – Software Design
Edgar Gabriel
Singleton
• Advantages:
– Compared to global variables, the singleton pattern avoids polluting the name space
– Permits refinement of operations, since it can be subclassed
– When subclassing, a registry of singletons is often used, which maps a name (i.e. string) to a particular Singleton
25
COSC 3351 – Software Design
Edgar Gabriel
Implementation
class Singleton {
public:
static Singleton* Instance();
protected:
Singleton();
private:
static Singleton* _instance;
}
Singleton* Singleton::_instace = 0;
Singleton* Singleton::Instance() {
if ( _instance == 0 ) {
_instance = new Singleton;
}
return _instance;
}
COSC 3351 – Software Design
Edgar Gabriel
Usage for the Maze game
• Well, no way to express the code using Singleton
• However, you will have to ensure typically, that only a
single instance of the Maze Factory is created and used
by all subcomponents of the game. Thus, the Maze
Factory should subclass Singleton.