0% found this document useful (0 votes)
85 views73 pages

02a3creational Design Patterns

The document discusses various creational design patterns including Factory Method, Abstract Factory, and Singleton patterns. It provides examples of how these patterns can be applied when building a maze game. The Factory Method pattern abstracts object creation so that subclasses can determine which objects to create. The Abstract Factory pattern provides a interface for creating families of related objects without specifying their concrete classes. The Singleton pattern ensures that only one instance of a class exists.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
85 views73 pages

02a3creational Design Patterns

The document discusses various creational design patterns including Factory Method, Abstract Factory, and Singleton patterns. It provides examples of how these patterns can be applied when building a maze game. The Factory Method pattern abstracts object creation so that subclasses can determine which objects to create. The Abstract Factory pattern provides a interface for creating families of related objects without specifying their concrete classes. The Singleton pattern ensures that only one instance of a class exists.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 73

Creational Design

Patterns
 Creational DP:
 Abstracts the instantiation process.
 Help make a system independent of how objects are
created, composed, represented.
 Two types of Creational Patterns
1. Class creational patterns
Use inheritance to vary the class that is instantiated
2. Object creational patterns
Delegates instantiation to another object
Creational Design
Patterns
 Two recurring themes in these patterns
1. They encapsulate knowledge about which
concrete classes the system use.
2. They hide how instances of these classes are
created and put together.
 The system only knows the interfaces.
 Creational DP-s let you configure the system
with “product” objects
 Configuration can be static (compile-time) or
dynamic (run-time).
Example: To build a
Maze
Maze Example –
MapSite Abstract class

enum Direction
{ North, South, East, West } ;

class MapSite {
public:
void Enter() = 0 ;
} ;
Maze Example –
Room
class Room: public MapSite
{
public:
Room(int roomNo) ;
{ roomNumber = number ; }
MapSite* GetSide(Direction d) const
{ return sides[d] ; }
void SetSide(Direction d, MapSite* m)
{ sides[d] = m ; }
virtual void Enter()
{ /* … do something … */ }
private:
MapSite* sides[4] ;
int roomNumber ;
} ;
Maze Example –
Wall and Door
class Wall: public MapSite {
public:
Wall() ;
virtual void Enter() ;
} ;
class Door: public MapSite {
public:
Door(Room*=0, Room*=0) ;
virtual void Enter() ;
Room* OtherSideFrom(Room*);
private:
Room* room1 ;
Room* room2 ;
bool isOpen;
} ;
Maze Example –
Collection of Rooms
class Maze {
public:
Maze() ;
void addRoom(Room r) ;
Room* RoomNo(int) const;
private:
// …
};
Maze Example –
Creation of Maze
class MazeGame
{
public:
Maze* CreateMaze() {
Maze* maze = new Maze() ;
Room* room1 = new Room(1) ;
Room* room2 = new Room(2) ; Room 1 Room 2
Door* door = new Door(room1,room2) ;
maze->AddRoom(room1) ;
maze->AddRoom(room2) ;
room1->SetSide(North, new Wall()) ;
room1->SetSide(East , door) ;
room1->SetSide(South, new Wall()) ;
room1->SetSide(West , new Wall()) ;
room2->SetSide(North, new Wall()) ;
room2->SetSide(East , new Wall()) ;
room2->SetSide(South, new Wall()) ;
room2->SetSide(West , door) ;
return maze ;
}
}
Creational Patterns
 Factory Method
 Create-Maze calls virtual functions to create
components
 Abstract Factory
 Create-Maze is passed an object to use to create
components
 Prototype
 Create-Maze is parameterized by various prototypes
 Builder
 Create-Maze is passed an object that can create
entire Maze
 Singleton
 Can ensure that there is only one maze per game.
Factory Method
 Intent: Define an interface for creating an object,
but let subclasses decide which class to
instantiate.
 Motivation:
 Example: Framework of Abstract classes
○ Abstract classes: Document, Application
 Application has Open, New, etc. to create new documents
 Application cannot know which concrete document to
instantiate
○ Concrete classes: DrawingDocument,
DrawingApplication
 Factory Method encapsulates the knowledge of
which Document subclass to create and move this
knowledge out of the framework.
Factory Method –
Motivation

 CreateDocument() is called Factory Method


Factory Method –
Maze Example
class MazeGame
{
public:
virtual Maze* MakeMaze() const { return new
Maze() ; }
virtual Room* MakeRoom(int n) { return new Room(n) ;
}
virtual Wall* MakeWall() { return new Wall() ; }
virtual Door* MakeDoor(Room* r1, Room* r2)
{ return new Door(r1,r2) ; }
Maze* CreateMaze() {
Maze* maze = MakeMaze() ;
Room* room1 = MakeRoom(1) ;
Room* room2 = MakeRoom(2) ;
Door* door = MakeDoor(room1,room2) ;
………
………
return maze ;
}
} ;
Factory Method –
Maze, Customized Components
class BombedWall: public Wall {
// …
} ;

class RoomWithABomb: public Room {


public:
RoomWithABomb(int n) : Room(n) { }
} ;

class BombedMazeGame: public MazeGame {


public:
BombedMazeGame();
virtual Wall* MakeWall()
{ return new BombedWall() ; }
virtual Room* MakeRoom(int n)
{ return new RoomWithABomb(n) ; }
} ;
Factory Method –
Applicability
 Use the Factory Method 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
Factory Method –
Structure
In more details
Factory Method -
Participants
 Product (Document)
 The interface of objects the Factory Method creates
 ConcreteProduct (MyDocument)
 Implements the product interface
 Creator (Application)
 Declares the factory method which returns an object of
type Product
 ConcreteCreator (MyApplication)
 Defines the Factory method to returnn an instance of
ConcreteProduct
Factory Method –
Consequences
 Eliminates the need to bind application-
specific classes into the code.
 Disadvantage: Clients might have to
subclass the Creator class just to create
a particular ConcreteProduct.
 Provides hooks for subclasses to create
extended version of an object.
 Connects parallel class hierarchies.
Factory Method –
Implementation Issues
1. Two Major Varieties
 Creator class has abstract factory methods
 Creator class defines default behavior for factory
methods
2. Parameterized Factory Methods
 One factory method can create multiple kinds of
products.
 All objects must have the same interface.
 Factory method can take a class ID.
3. Language-specific issues.
 Creator can keep the Class information for creating new
instances, dropping the need for the sub-classing.
4. Templates can be used to avoid subclassing.
Abstract Factory
 Intent: Provides an interface for creating
families of related or dependent objects
without specifying their concrete classes.
 Motivation:
 User interface Toolkit supporting multiple look-and-
feel standards. (Widgets like Scroll Bars, Windows,
Buttons etc.)
 Not to hard code these widgets for a particular look-
and-feel otherwise hard to change it
 We can define a WidgetFactory interface for creating
each basic entity
 Widget Factory enforces dependencies between the
concrete Widget classes
Abstract Factory
Example
One more example
Factory Method –
Maze Example
class MazeFactory {
public:
Maze* MakeMaze() { return new Maze() ; }
Room* MakeRoom(int n) { return new Room(n) ; }
Wall* MakeWall() { return new Wall() ; }
Door* MakeDoor(Room r1, Room r2)
{ return new Door(r1,r2) ; }
} ;
class MazeGame {
public:
Maze* CreateMaze(MazeFactory* factory) {
Maze* maze = factory->newMaze() ;
Room* room1 = factory->newRoom(1) ;
Room* room2 = factory->newRoom(2) ;
Door* door = factory->newDoor(room1,room2) ;
………
return maze ;
}
} ;
Factory Method –
Maze Example
class BombedWall: public Wall {
// …
} ;

class RoomWithABomb: public Room {


public:
RoomWithABomb(int n) : Room(n) { }
} ;

class BombedMazeFactory: public MazeFactory {


public:
BombedMazeGame();
virtual Wall* MakeWall()
{ return new BombedWall() ; }
virtual Room* MakeRoom(int n)
{ return new RoomWithABomb(n) ; }
} ;
Abstract Factory –
Applicability
 Use Abstract Factory if
A system must be independent of how its
products are created
A system should be configured with one of
multiple families of products
A family of related objects must be used
together
You want to reveal only interfaces of a
family of products and not their
implementations
Abstract Factory –
Structure
In more detail
Abstract Factory –
Participants
 AbstractFactory (WidgetFactory)
 Declares an interface of methods to create abstract
product objects
 ConcreteFactory (MotifWidgetFactory,…)
 Implements the methods to create concrete product
objects
 AbstractProduct (Window, ScrollBar)
 Declares an interface for a product type
 ConcreteProduct (MotifWindow, MotifScrollBar)
 Defines a product object
 Implements the AbstractProduct interface
 Client
 Uses only interfaces declared by AbstractFactory and
AbstractProduct
Abstract Factory –
Consequences

1. It isolates concrete classes


2. It makes exchanging product families
easy
3. It promotes consistency among
products
4. Supporting new kinds of products is
difficult
Abstract Factory –
Implementation
 Factory better to be a Singleton
 If many product families are possible, the
Concrete Factory can be implemented using
Prototype. Or alternatively the Class
information of products can be kept (for
languages supporting Class information).
 Defining Extensible Factories: Adding a new
Product type means to change
AbstractFactory and all its subclasses. A more
flexible but less safe design is to add a
parameter to operations that create objects.
Singleton
 Intent: Ensure that a class has only one
instance, and provide a global point of access
to it.

 Use Singleton
 There must be exactly one instance of a class, and it
must be accessible to clients from a well known
access point.
 When this instance should be extensible by sub-
classing
Singleton

 Singleton
 Define an Instance operation to access its unique
instance. It must be a static method.
 Must create its own unique instance.
Singleton –
Benefits
1. Controlled access to sole instance
2. Reduced namespace
3. May be sub-classed to refine
operations
4. Can Permit a variable number of
instances
5. More flexible than static methods
Singleton –
Implementation
 Ensure a unique instance
class Singleton {
private: static Singleton* inst = 0 ;
protected: Singleton() { }
public: static Singleton* getInstance() {
if (inst==0) inst = new Singleton() ;
return inst ;
}
} ;
 Subclassing the singleton class
 How to install the unique instance?
○ To determine it in getInstance() method
○ To rewrite getInstance() in the subclass
○ To keep registry of Singletons
Singleton –
Maze Factory
class MazeFactory {
protected: MazeFactory() { }
private: static MazeFactory* inst = null ;
public: static MazeFactory* getInst()
{ if (inst==null) inst = new MazeFactory() ;
return inst ; }
Maze* makeMaze()
{ return new Maze() ; }
Room* makeRoom(int n)
{ return new Room(n) ; }
Wall* makeWall()
{ return new Wall() ; }
Door* makeDoor(Room r1, Room r2)
{ return new Door(r1,r2) ; }
} ;
Singleton –
Maze Example
class MazeGame
{
public:
Maze* createMaze() {
Maze maze* = MazeFactory.getInst()->MakeMaze() ;
Room room1* = MazeFactory.getInst()-
>MakeRoom(1) ;
Room room2* = MazeFactory.getInst()-
>MakeRoom(2) ;
Door door* =
MazeFactory.getInst()->MakeDoor(room1,room2) ;

maze->AddRoom(room1) ;
maze->AddRoom(room2) ;
………
return maze ;
}
}
Singleton –
Alternative Maze Factory
MazeFactory* MazeFactory::getInst()
{ if (inst==0) {
const char* style = getenv("MAZESTYLE")
;
if (strcmp(style,"BOMBED“))
inst = new BombedMazeFactory() ;
else if (strcmp(style,"BOMBED“))
inst = new
EnchantedMazeFactory() ;
else
inst = new MazeFactory() ;
}
return inst ; }
Template Singleton
Class
// in .h
template <class T>
class Singleton : public T
{
public:
static Singleton* GetInstance()
{
if (! ptrSingObject)
ptrSingObject = new Singleton ;
return ptrSingObject ;
}
~Singleton() { delete ptrSingObject ; }
private:
Singleton() { } ;
static Singleton* ptrSingObject ;
};
// In .cpp
template <class T>
Singleton<T>* Singleton<T>::ptrSingObject = NULL ;
// usage
class CMyClass {
void myfunc() ;
} ;
// In the program to use
Singleton<CMyClass>::GetInstance()->myfunc() ;
Singleton in multi-threaded
environment
 Singletons used in multi-theaded systems are
susceptible to a “race” condition during execution of
the instance() function which can allow creation of
multiple instances (oh oh…multiple singletons?) and
cause a memory leak.
 Threads can try to update the same data structure at
the same time.
The result can be partly what one thread wrote and
partly what the other thread wrote.
This garbles the data structure, typically causing the
next thread that tries to use it to
crash
Solution
 In the instance() function, if self  is zero,
then aquire a lock (semaphore, mutex,
etc.). Next, double check to insure that
self is still zero If self is still zero, then
create an instance of the Singleton and
assign it to self. Release the lock and
return.
Example code
class Singleton { 
public: 
 static Singleton * instance();
    private: 
 static Singleton * self; 
 static SEMAPHORE key
}
Singleton * Singleton::instance() {
    if (self == 0) {
          if ( lock(key) >= 0 ) {
                if (self == 0 ) //double-check!
                      self = new Singleton;
                unlock (key);
}}}

 Thanks to Moshe Fresko


 References: GOF
Builder
 Intent: Separate the construction of a complex object
from its representation so that the same construction
process can create different representations.
 Motivation:
 An RTF reader should be able to convert an RTF
document to many text formats. The number of possible
conversions are open-ended.
○ Plain ASCII Text
○ Text Widget for Editing
 RTF-Reader parses the RTF document. It uses Text-
Converter to perform the conversion.
 Whenever the RTF-Reader recognizes an RTF token it
issues a request to the Text-Converter to convert the
token.
Builder – Motivation

 Each converter class is called a Builder, and the


reader is called the Director.
Builder –
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
is constructed.
Builder –
Structure
Builder - Participants
 Builder (TextConverter)
 Specifies an abstract interface for creating parts of a
product object.
 ConcreteBuilder (AsciiConverter, TeXConverter, …)
 Constructs and assembles parts of products
 Defines and keeps track of the representation it creates
 Provides an interface for retrieving the product
 Director (RTFReader)
 Constructs an object using the Builder interface
 Product (AsciiText, TeXText, …)
 Represents the complex object under construction
Builder – Director
cooperation
Builder – Consequences
1. It let’s you vary a product’s internal
representation
2. It isolates code for construction and
representation
3. It gives you finer control over the
construction process
Builder –
Implementation Issues
1. Assembly and Construction Interface
 Builders construct their products step-by-step.
○ Usually appending simply the parts is enough.
○ Sometimes access to parts is needed. (Door
between rooms, children nodes for a tree
structures)
2. Why no abstract class for products?
 The products differ greatly.
 The client configures the director with the
concrete builder.
3. Empty methods as default in builder.
Builder – Sample Code
class MazeBuilder {
public:
virtual void BuildMaze() { }
virtual void BuildRoom(int n) { }
virtual void BuildDoor(int nfrom, int nto) { }
virtual Maze* GetMaze() { return 0 ; }
protected:
MazeBuilder() ;
} ;

Maze* MazeGame::CreateMaze(MazeBuilder& builder) {


builder.BuildMaze() ;
builder.BuildRoom(1) ;
builder.BuildRoom(2) ;
builder.BuildDoor(1,2) ;
return builder.GetMaze() ;
}
Builder – Sample Code

Maze* MazeGame::CreateComplexMaze ( MazeBuilder& builder) {


builder.BuildMaze() ;
builder.BuildRoom(1) ;
builder.BuildRoom(2) ;
builder.BuildDoor(1,2) ;

builder.BuildRoom(1000) ;
return builder.GetMaze() ;
}
Builder – Sample Code
class StandardMazeBuilder : public MazeBuilder {
private:
Maze* currentMaze ;
public:
StandardMazeBuilder() : currentMaze(0)
{ }
virtual void BuildMaze()
{ currentMaze = new Maze() ; }
Maze* GetMaze()
{ return currentMaze ; }
virtual void BuildRoom(int n)
{ if (! currentMaze->RoomNo(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()) ;
}
}
virtual void BuildDoor(int n1,int n2) {
Room* r1 = currentMaze->RoomNo(n1) ;
Room* r2 = currentMaze->RoomNo(n2) ;
Door* d = new Door(r1,r2) ;
r1->SetSide(CommonWall(r1,r2),d) ;
r2->SetSide(CommonWall(r2,r1),d) ;
}
} ;
Builder – Sample Code
 Usage
Maze* maze;
MazeGame game;
StandardMazeBuilder builder;
game.CreateMaze(builder);
maze = builder.GetMaze();
Builder – Sample Code
 Another builder for counting
class CountingMazeBuilder : public MazeBuilder {
private:
int doors;
int rooms;
public:
CountingMazeBuilder(): doors(0), rooms(0)
{ }
virtual void BuildMaze()
{ doors=0; rooms=0; }
virtual void BuildRoom(int i)
{ rooms++; }
virtual void BuildDoor(int r1,int r2)
{ doors++; }
void GetCounts(int& roomcount, int& doorcount)
{ roomcount=rooms; doorcount=doors; }
};
Builder – Sample Code
int rooms, doors;
MazeGame game;
CountingMazeBuild builder;
game.CreateMaze(builder);
builder.GetCounts(rooms,doors);
cout<< “The maze has ”
<< rooms << “ rooms and ”
<< doors << “ doors” << endl
;
Prototype
 Intent: Specify the kinds of objects to create using a
prototypical instance, and create new objects by
copying this prototype.
 Motivation:
 To build an editor for music scores by customizing a
general framework for graphical editors and adding new
objects that represent notes, rests and staves.
 Let’s have a Graphic class for graphic components like
notes (a quarter-note), staves, etc. And a GraphicTool
class for adding such components.
 The classes of notes and staves are specific to
application and GraphicTool is a general framework.
Subclassing GraphicTool needs a subclass for each
Graphic class. It is better to use composition.
 Solution is to add a cloning instance (Prototype) into
GraphicTool.
Prototype – Motivation
Prototype – Applicability
 Use Prototype pattern when a system
should be independent of how its
products are created, composed, and
represented; and
When the classes to instantiate are
specified at run-time
To avoid building class-hierarchy of factories
that parallels the class hierarchy of products
When instances of a class can have only
one of a few different combinations of
states.
Prototype – Structure
Prototype – Participants
 Prototype (Graphic)
 Declares an interface for cloning itself

 ConcretePrototype (Staff, WholeNote,


HalfNote)
 Implements an operation for cloning itself

 Client (GraphicTool)
 Creates a new object by asking a prototype to clone
itself.
Prototype –
Consequences
 It hides concrete product classes from the
client
 Let a client work with application-specific
classes without modification
1. Adding and removing products at run-time.
2. Specifying new objects by varying values.
3. Specifying new objects by varying structure.
4. Reduced subclassing.
5. Configuring an application with classes
dynamically.
 Adding Clone() to each product may be
difficult.
Prototype –
Implementation Issues
1. Using a prototype manager.
To keep a registry of possible
prototypes.
2. Implementing the Clone operation.
Shallow Copy versus Deep Copy.
Serialization (Save-Load) can be used
for cloning.
3. Initializing clones.
Set operations can solve this problem.
Prototype – Sample
class MazePrototypeFactory : public MazeFactory {
private:
Maze* pMaze; Wall* pWall; Room* pRoom; Door* pDoor;
public:
MazePrototypeFactory ( Maze* m, Wall* w, Room* r, Door* d)
: pMaze(m), pWall(w), pRoom(r), pDoor(d)
{ }
virtual Maze* MakeMaze() const
{ return pMaze->Clone() ; }
virtual Room* MakeRoom(int r) const
{ Room* p = pRoom->Clone() ;
p->initialize(r) ;
return p; }
virtual Wall* MakeWall() const
{ return pWall->Clone(); }
virtual Door* MakeDoor(Room* r1, Room* r2) const
{ Door* door = pDoor->Clone();
door->initialize(r1,r2);
return door; }
};
Prototype – Sample
MazeGame game;

MazePrototypeFactory simpleMazeFactory(new
Maze, new Wall, new Room, new Door);

MazePrototypeFactory bombedMazeFactory(new
Maze, new BombedWall, new RoomWithABomb,
new Door);

Maze* maze1 =
game.CreateMaze(simpleMazeFactory);

Maze* maze2 =
game.CreateMaze(bombedMazeFactory);
Prototype – Sample
class Door: public MapSite {
private:
Room* room1;
Room* room2;
public:
Door(): room1(0), room2(0)
{ }
Door(const Door& d): room1(d.room1), room2(d.room2)
{ }
virtual void Initialize(Room* r1, Room* r2)
{ room1 = r1 ;
room2 = r2 ; }
virtual Door* Clone() const {
return new Door(*this) ;
}
} ;
Prototype – Sample Code
class BombedWall: public Wall {
private:
bool bomb;
public:
BombedWall() : bomb(true)
{ }
BombedWall(bool b) : bomb(b)
{ }
BombedWall(const BombedWall& other)
{ bomb = other.bomb; }
virtual Wall* Clone() const
{ return new BombedWall(*this) ; }
bool HasBomb()
{ return bomb; }
} ;
Creational Design Patterns

Discussion
 Two ways two parameterize a system by the
classes of objects it creates.
1. To subclass the class that creates objects
- Factory Method
Main drawback is that it requires a new subclass
just to change the class of the product.
2. By object composition
- Abstract Factory: Factory Object producing
objects of several classes
- Builder: Factory Object building a complex product
- Prototype: Factory Object building a product by
copying a prototype object.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy