290 likes | 392 Views
02 - Creational Design Patterns – 2. Moshe Fresko Bar-Ilan University תשס"ח 2008. Builder. Moshe Fresko Bar-Ilan University תשס"ו - 2005-2006 Design Patterns Course. Builder.
E N D
02 - Creational Design Patterns – 2 Moshe Fresko Bar-Ilan University תשס"ח 2008
Builder Moshe Fresko Bar-Ilan University תשס"ו - 2005-2006 Design Patterns Course
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 - 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 – Consequences • It let’s you vary a product’s internal representation • It isolates code for construction and representation • It gives you finer control over the construction process
Builder – Implementation Issues • 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) • Why no abstract class for products? • The products differ greatly. • The client configures the director with the concrete builder. • 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 Moshe Fresko Bar-Ilan University תשס"ו - 2005-2006 Design Patterns Course
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 – 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 – 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 • Adding and removing products at run-time. • Specifying new objects by varying values. • Specifying new objects by varying structure. • Reduced subclassing. • Configuring an application with classes dynamically. • Adding Clone() to each product may be difficult.
Prototype – Implementation Issues • Using a prototype manager. To keep a registry of possible prototypes. • Implementing the Clone operation. Shallow Copy versus Deep Copy.Serialization (Save-Load) can be used for cloning. • 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. • To subclass the class that creates objects- Factory MethodMain drawback is that it requires a new subclass just to change the class of the product. • 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.