Creational Patterns, Abstract Factory, Builder Billy Bennett June 11, 2009.

Post on 14-Dec-2015

221 views 2 download

Tags:

Transcript of Creational Patterns, Abstract Factory, Builder Billy Bennett June 11, 2009.

Creational Patterns,Creational Patterns,Abstract Factory,Abstract Factory,BuilderBuilder

Billy BennettJune 11, 2009

Creational PatternsCreational Patterns

Two Recurring Themes:

1.Encapsulate knowledge about which concrete classes the system uses.

2.Hide how these instances are created and put together.

The Maze ExampleThe Maze Example

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;

}

Uh-ohUh-ohThis gets complicated.It’s inflexibly coded.It’s difficult to reuse.Only makes 2 rooms.Creational patterns let us make

this design more flexible and thus more reusable.

Potential PatternsPotential PatternsVirtual functions instead of

constructors for◦Rooms◦Doors◦Walls

Make a subclass of MazeGame to redefine these functions

Factory Method

Potential PatternsPotential PatternsCreateMaze is passed an object

as a parameter, which is used to change the classes used to make◦Rooms◦Doors◦Walls

Abstract Factory

Potential PatternsPotential PatternsCreateMaze is passed an object

that can create a maze all by itself, then you can use inheritance to change parts of the maze:◦Rooms◦Doors◦Walls

Builder

Potential PatternsPotential PatternsCreateMaze is parameterized by

various prototypical:◦Rooms◦Doors◦Walls

You can replace these prototypical objects with different ones to change the maze

Prototype

Abstract FactoryAbstract Factory

Abstract FactoryAbstract FactoryIntent

◦Provide an interface for creating families of related or dependent objects without specifying their concrete classes

A.K.A.◦“Kit”

ApplicabilityApplicabilityA system should be independent of

how its products are created, composed, or 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

You want to provide a class library of objects, but reveal only their interfaces

ParticipantsParticipantsClientAbstractFactoryConcreteFactoryAbstractProductConcreteProduct

ConsequencesConsequences

1. Concrete class isolation (Good)• Client does not interact with the

implementation classes• Client only manipulates instances

through the abstract interfaces

ConsequencesConsequences

2. Product families easily exchanged (Good)• Only have to change the concrete

factory• Can be done at run time

ConsequencesConsequences

3. Products are more consistent (Good)• Helps the products in each product

family consistently be applied together (assuming they work well together)

• Only one family at a time

ConsequencesConsequences

4. Difficult to support new kinds of products (Bad)• Extending existing abstract

factories to make new products is difficult and time consuming

• The family of products available is fixed by Abstract Factory interface

Implementation IssuesImplementation IssuesConcrete Factories make excellent

Singletons (not necessarily one factory, but one per product family)

Factory Methods within Concrete Factories for each product, or Prototypes if many product families

Move implementation one step closer to Client by adding a parameter specifying product type (less safe, more extensible)

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)

{return new Door(r1, r2);}

};

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;

}

Maze* MazeGame::CreateMaze (MazeFactory& factory)

{

Maze* aMaze = factory.MakeMaze();

Room* r1 = factory.MakeRoom (1);

Room* r2 = factory.MakeRoom (2);

Door* theDoor = factory.MakeDoor (r1, r2);

aMaze->AddRoom(r1);

aMaze->AddRoom(r2);

r1->SetSide(North, factory.MakeWall);

r1->SetSide(East, theDoor);

r1->SetSide(South, factory.MakeWall);

r1->SetSide(West, factory.MakeWall);

r2->SetSide(North, factory.MakeWall);

r2->SetSide(East, factory.MakeWall);

r2->SetSide(South, factory.MakeWall);

r2->SetSide(West, theDoor);

return aMaze;

}

Related PatternsRelated PatternsFactory MethodPrototypeSingleton

BuilderBuilderIntent

◦Separate the construction of a complex object from its representation so that the same construction process can create different representations

ApplicabilityApplicabilityThe algorithm for creating a

complex object should be independent of the parts that make up the object and how they’re assembled

The construction process must allow for different representations for that object that’s constructed

ParticipantsParticipantsDirectorBuilderConcrete BuilderProduct

ConsequencesConsequences

1. Varying a product’s internal representation (Good)• The Director doesn’t see the

product’s construction, only the Builder does

ConsequencesConsequences

2. Isolates code for construction and representation (Good)• The Client only retrieves the

product• The Client doesn’t know anything

about the internal construction of the product

• Question: Multiple directors?

ConsequencesConsequences

3. Step by step construction (Good?)• The Client only retrieves the

product• The Client doesn’t know anything

about the internal construction of the product

• Question: Multiple directors?

Implementation IssuesImplementation IssuesBuilder needs a very general

interfaceBuilder(s) may need access to a

variety of components – parse trees are one solution

No abstract product class (products are too different, commonly)

Class MazeBuilder {

public:

virtual void BuildMaze() {. . .}

virtual void BuildRoom (int room) {. . .}

virtual void BuildDoor (int roomFrom, int roomTo) {. . .}

virtual Maze* GetMaze() {return Maze to client}

Protected:

MazeBuilder();

};

Maze* MazeGame::CreateMaze (MazeBuilder& builder)

{

builder.BuildMaze();

builder.BuildRoom(1);

builder.BuildRoom(2);

builder.BuildDoor(1,2);

return builder.GetMaze();

}

Other thoughtsOther thoughtsThe “abstract interface” theme

among patternsOOP bias?Why do some patterns seem so

similar – is there a standard for defining novelty among patterns?