1 / 89

Chapter 3

Chapter 3. Creational Patterns. Design Patterns Elements of Reusable Object-Oriented Software. Creational Patterns. Creational design patterns abstract the instantiation process A class creational pattern uses inheritance to vary the class that’s instantiated

chaim
Télécharger la présentation

Chapter 3

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 3 Creational Patterns Design PatternsElements of Reusable Object-Oriented Software

  2. Creational Patterns • Creational design patterns abstract the instantiation process • A class creational pattern uses inheritance to vary the class that’s instantiated • An object creational pattern will delegate instantiation to another object

  3. Example: A Game of Maze MapSite Enter() sides Room Wall Door Enter() SetSide() GetSide() Enter() Enter() Maze isOpen rooms AddRoom() RoomNo() roomNumber

  4. Class - Mapsite class MapSite { public: virtual void Enter() = 0; }; enum Direction {North, South, East, West};

  5. Class - Room class Room : public MapSite { public: Room(int roomNo); MapSite* GetSide(Direction) const; void SetSide(Direction, MapSite*); virtual void Enter(); private: MapSite* _sides[4]; int _roomNumber; };

  6. Class - Wall class Wall : public MapSite { public: Wall(); virtual void Enter(); };

  7. Class - Door class Door : public MapSite { public: Door(Room* = 0, Room* = 0); virtual void Enter(); Room* OtherSideFrom(Room*); private: Room* _room1; Room* _room2; bool _isOpen; };

  8. Class - Maze class Maze { public: Maze(); void AddRoom(Room*); Room* RoomNo(int) const; private: // … };

  9. 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; } Class – MazeGame

  10. Making the design more flexible • CreateMaze calls virtual functions instead of constructor calls (Factory Method) • CreateMaze is passed an object as a parameter to use to create rooms, walls and doors (Abstract Factory) • CreateMaze is passed an object that can create a new maze in its entirety using operations for adding rooms, doors, and walls to the maze it builds (Builder) • CreateMaze is parameterized by various prototypical room, door, and wall objects, which it then copies and adds to the maze (Prototype) • The remaining creational pattern, Singleton, can ensure there’s only one maze per game and that all game objects have ready access to it – without resorting to global variables or functions

  11. Abstract Factory Object Creational

  12. Abstract Factory • Intent • Provide an interface for creating families of related or dependent objects without specifying their concrete classes • Also Known As • Kit

  13. Abstract Factory - Motivation WidgetFactory Client CreateScrollBar()CreateWindow() Window MotifWidgetFactory PMWindow MotifWindow CreateScrollBar()CreateWindow() ScrollBar PMWidgetFactory CreateScrollBar()CreateWindow() PMScrollBar MotifScrollBar

  14. Abstract Factory - Structure AbstractFactory Client CreateProductA()CreateProductB() AbstractProductA ConcreteFactory1 ProductA2 ProductA1 CreateProductA()CreateProductB() AbstractProductB ConcreteFactory2 CreateProductA()CreateProductB() ProductB2 ProductB1

  15. Abstract Factory - Consequences • Benefits • It isolates concrete classes • It makes exchanging product families easy • It promotes consistency among products • Liabilities • Supporting new kinds of products is difficult

  16. Abstract Factory - Implementation • Factories as singletons • Creating the products • Define a factory method for each product • Using the Prototype pattern • Defining extensible factories • Add a parameter (e.g. a class identifier or a class name) to operations that create objects • Problem: Needs downcast, which may not be safe

  17. Abstract Factory – Class - MazeFactory 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); } };

  18. 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) aMaze->AddRoom(r1); aMaze->AddRoom(r2); r1->SetSide(North, factory.MakeWall()); r1->SetSide(East, aDoor); r1->SetSide(South, factory.MakeWall()); r1->SetSide(West, factory.MakeWall()); Abstract Factory – MazeGame r2->SetSide(North, factory.MakeWall()); r2->SetSide(East, factory.MakeWall()); r2->SetSide(South, factory.MakeWall()); r2->SetSide(West, aDoor); return aMaze; }

  19. Abstract Factory – Class - EnchantedMazeFactory class EnchantedMazeFactory : public MazeFactory { public: EnchantedMazeFactory(); virtual Room* MakeRoom(int n) const { return new EnchantedRoom(n, CastSpell()); } virtual Door* MakeDoor(Room* r1, Room* r2) const { return new DoorNeedingSpell(r1, r2); } protected: Spell* CastSpell() const; };

  20. Abstract Factory – Class - BombedMazeFactory class BombedMazeFactory : public MazeFactory { public: BombedMazeFactory(); virtual Wall* MakeWall() const { return new BombedWall; } virtual Room* MakeRoom(int n) const { return new RoomWithABomb(n); } };

  21. Abstract Factory – Using the Factory MazeGame game; BombedMazeFactory factory; game.CreateMaze(factory); • A “RoomWithABomb” can safely assume that its walls are “BombedWall”s if walls are built solely with a “BombedMazeFactory”.

  22. Abstract Factory – Related Patterns • AbstractFactory classes are often implemented with factory methods, but they can also be implemented using Prototype • A concrete factory is often a singleton

  23. Builder Object Creational

  24. Builder • Intent • Separate the construction of a complex object from its representation so that the same construction process can create different representations

  25. while(t=get the next token) { switch t.Type { CHAR: builder->ConvertCharacter(t.CHAR) FONT: builder->ConvertFontChange(t.FONT) PARA: builder->ConvertParagraph() } } Builder – Motivation (1) RTFReader builders TextConverter builder ParseRTF() ConvertCharacter(char)ConvertFontChange(Font)ConvertParagraph() ASCIIConverter TeXConverter TextWidgetConverter ConvertCharacter(char)GetASCIIText() ConvertCharacter(char)ConvertFontChange(Font)ConvertParagraph()GetTeXText () ConvertCharacter(char)ConvertFontChange(Font)ConvertParagraph()GetTextWidget() ASCIIText TeXText TextWidget

  26. Builder – Motivation (2) • Each converter class is called a builder • The reader is called the director

  27. for all objects in structure { builder->BuildPart()} Builder – Structure Director Builder builder Construct() BuildPart() ConcreteBuilder Product BuildPart()GetResult()

  28. Builder – Collaborations aClient aDirector aConcreteBuilder new ConcreteBuilder new Director(aConcreteBuilder) Construct() BuildPartA() BuildPartB() BuildPartC() GetResult()

  29. Builder - Consequences • It lets the programmer vary a product’s internal representation • It isolates code for construction and representation • It gives the programmer finer control over the construction process

  30. Builder - Implementation • Assembly and construction interface • Why no abstract class for products? • Empty methods as default in Builder • The parent builder class (or topmost class in any hierarchy) need not be an abstract class. It can have default implementation of different virtual functions and act as a concrete class.

  31. Builder – Class - MazeBuilder Ref: The UML model

  32. Builder – Class - MazeBuilder class MazeBuilder { public: virtual void BuildMaze() { } virtual void BuildRoom(int room) { } virtual void BuildDoor(int roomFrom, int roomTo) { } virtual Maze* GetMaze() { return 0; } protected: MazeBuilder(); };

  33. Builder – Class - MazeGame Maze* MazeGame::CreateMaze (MazeBuilder& builder) { builder.BuildMaze(); builder.BuildRoom(1); builder.BuildRoom(2); builder.BuildDoor(1, 2); return builder.GetMaze(); }

  34. Builder – Class - MazeGame Maze* MazeGame::CreateComplexMaze (MazeBuilder& builder) { builder.BuildRoom(1); // … builder.BuildRoom(1001); return builder.GetMaze(); }

  35. Builder – Class – StandardMazeBuilder (1) class StandardMazeBuilder : public MazeBuilder { public: StandardMazeBuilder(); virtual void BuildMaze(); virtual void BuildRoom(int); virtual void BuildDoor(int, int); virtual Maze* GetMaze(); private: Direction CommonWall(Room*, Room*); Maze* _currentMaze; };

  36. Builder – Class – StandardMazeBuilder (2) StandardMazeBuilder::StandardMazeBuilder () { _currentMaze = 0; } void StandardMazeBuilder::BuildMaze () { _currentMaze = new Maze; } Maze* StandardMazeBuilder::GetMaze () { return _currentMaze; }

  37. Builder – Class – StandardMazeBuilder (3) void StandardMazeBuilder::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); } };

  38. Builder – Class – StandardMazeBuilder (4) void StandardMazeBuilder::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); };

  39. Builder – Using the Builder Maze* maze; MazeGame game; StandardMazeBuilder builder; game.CreateMaze(builder); maze = builder.GetMaze();

  40. Builder – Class – CountingMazeBuilder (1) class CountingMazeBuilder : public MazeBuilder { public: CountingMazeBuilder(); virtual void BuildMaze(); virtual void BuildRoom(int); virtual void BuildDoor(int, int); virtual void AddWall(int, Direction); void GetCounts(int&, int&) const; private: int _doors; int _rooms; };

  41. Builder – Class – CountingMazeBuilder (2) CountingMazeBuilder:: CountingMazeBuilder () { _rooms = _doors = 0; } void CountingMazeBuilder::BuildRoom (int) { _rooms++; } void CountingMazeBuilder::BuildDoor (int, int) { _doors++; } void CountingMazeBuilder::GetCounts (int& rooms, int& doors) const { rooms = _rooms; doors = _doors; }

  42. Builder – Using CountingMazeBuilder int rooms, doors; MazeGame game; CountingMazeBuilder builder; game.CreateMaze(builder); builder.GetCounts(rooms, doors); cout << “The Maze has ” << rooms << “ rooms and ” << doors << “ doors” << endl;

  43. Builder Focuses on constructing a complex object step by step Returns the product as a final step Abstract Factory Emphasis is on families of product objects (either simple or complex) The product gets returned immediately Builder – Related Patterns A Composite is what the builder often builds

  44. Factory Method Class Creational

  45. 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 • Also Known As • Virtual Constructor

  46. Document* doc = CreateDocument(); docs.Add(doc); doc->Open(); return new MyDocument; Factory Method - Motivation docs Document Application Open()Close() Save() Revert() CreateDocument()NewDocument()OpenDocument() MyDocument MyApplication CreateDocument()

  47. product = FactoryMethod() return new ConcreteProduct Factory Method - Structure Creator FactoryMethod()AnOperation Product ConcreteProduct ConcreteCreator FactoryMethod()

  48. Factory Method - Consequences • Clients might have to subclass the Creator class just to create a particular ConcreteProduct Object – a potential disadvantage • Connects parallel class hierarchies • See next slide for an example

  49. Factory Method – Parallel Class Hierarchies Figure Client Manipulator CreateManipulator()… DownClick()Drag() UpClick() LineFigure TextManipulator CreateManipulator()… DownClick()Drag() UpClick() LineManipulator DownClick()Drag() UpClick() TextFigure CreateManipulator()…

  50. Factory Method – Implementation • Create objects in a separate operation so that subclasses can override the way they’re created • Parameterized factory methods • Just be careful not to call factory methods in the Creator’s constructor – the factory method in the ConcreteCreator won’t be available yet • Use “lazy initialization” • Using templates to avoid subclassing

More Related