l11-12: design patterns definition iterator (l4: inheritance) factory (l4: inheritance) strategy...
TRANSCRIPT
L11-12: Design Patterns•Definition
•Iterator (L4: Inheritance)
•Factory (L4: Inheritance)
•Strategy (L5: Multiple Inheritance)
•Composite (L6: Implementation Issues)
•Template Method (L6: Implementation Issues)
•Abstract Factory (L7: Polymorphism1)
•Singleton (L8: Polymorphism2)
•Prototype (L9 : Design by Contract)
•Adapter (L10: Exceptions)
•Facade (L10: Exceptions)
•Proxy (L10: Exceptions)
Design Patterns
Definition:“Each pattern describes a problem which occurs over and over again in the environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.”
Classic Reference
• Chapter 24 of Budd.
“Design Patterns: Elements of Reusable Object-Oriented Software”, by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.
COSC346 - Pattern of the Day - Lecture 10
4
Iterator
Problem: How to provide a way to access elements of an aggregate object sequentially without exposing the underlying representation.
Solution: Provide an iterator object for the sole purpose of sequential access.
COSC346 - Pattern of the Day - Lecture 10
5
Examplevector<int> vec;vector<int>::iterator iter;// add stuff to vec…// now traverse vecfor (iter=vec.begin(); iter!=vec.end(); iter+
+) {
cout << *iter << endl;}
COSC346 - Pattern of the Day - Lecture 10
6
Consequences
• Makes changing the order of iteration easy• Simplifies the aggregate’s interface• Can traverse an aggregate more than once at
the same time
COSC346 - Pattern of the Day - Lecture 10
7
Iterators and Algorithms
#include <algorithm>
vector<int> vec;
sort(vec.begin(), vec.end());
random_shuffle(vec.begin(), vec.end());
int mx = max(vec.begin(), vec.end());
Factory Method
Problem: You have a method that returns a newly created object, but you want subclasses to have the ability to return different types of objects.
Solution: Allow the subclass to override the creation method and return a different type of object.
Exampleclass BoardGame {
private:
Board gameBoard;
public:
BoardGame() {gameBoard = makeGameBoard();pieces = makeInitialPieces();gameBoard.add(pieces); };
virtual Board *makeGameBoard() = 0;virtual Vector<Pieces *> makeInitialPieces() = 0;
}class OthelloBoardGame : public BoardGame {
public:
virtual Board *makeGameBoard() {return new OthelloBoard();};
}
Consequences
• Eliminates the need to bind application-specific classes into code.
• May cause a large class hierarchy.
Strategy
Problem: How do you allow the algorithm that is used to solve a particular problem be easily and dynamically changed by the client?
Solution: Define a family of algorithms with a similar interface.
Exampleclass SortableVector: public vector {
private: Sorter _sorter;
public: void sort() {_sorter.sort(this);
}}class Sorter {
public: virtual void sort(SortableVector tosort)=0;}class QuickSorter : public Sorter {
public: void sort(SortableVector tosort) {...
}}
Consequences
• Families of related algorithms.
• Alternative to subclassing.
• Eliminates conditional statements.
• Clients must be aware of different strategies.
• Increases the number of objects.
Composite
Scope: ObjectProblem: How do you permit the creation of
complex objects using only simple parts?Solution: Provide a small collection of simple
components but allow these components to be nested arbitrarily
Example
Consequences
• Makes the client simple• Makes it easy to add new kinds of
components• Can make the design overly general
Template Method
Scope: ClassProblem: How do we avoid code duplication
when subclasses share similar parts of an algorithm?
Solution: Provide a template method that implements the invariant part of the algorithm and makes calls to subclass specific methods.
Exampleclass GamePlayer {private:
Player p1, p2;public:
void playGame() {do {
p1.makeMove();if (!checkWin())
p2.makeMove();} while (!checkWin());
}virtual void makeMove()=0;virtual boolean checkWin()=0;
}
Consequences
• Fundamental for code reuse• Important for class libraries• Factors out common behaviours• Parent class calls the operations of a
subclass
Abstract Factory
Problem: How to provide a mechanism for creating instances of families of related objects without specifying their concrete representations?
Solution: Provide a method that returns a new value that is characterised only by an interface or parent class.
class ChessPieceFactory {public: virtual Pawn *makePawn()=0; virtual Rook *makeRook()=0;};class ChessPieceFactory2D: public ChessPieceFactory {public: Pawn *makePawn() { // make a 2d pawn } Rook *makeRook() { // make a 2d rook }};
void addPiecesToBoard() { Position pos1, pos2, pos3;
addPiece(factory->makePawn(), pos1);addPiece(factory->makePawn(), pos2);addPiece(factory->makeRook(), pos3);
}
Consequences
• Isolates concrete classes• Makes exchanging product families easy• Promotes consistency among products• Supporting new kinds of products is
difficult
23
Singleton
Problem: How do we ensure that there will never be more than one instance of a class created?
Solution: Create a class that only allows one instance of itself.
24
Exampleclass Singleton{public: static Singleton &theOne(){ return *the_one;};private: Singleton(){}; static Singleton *the_one;};...Singleton *Singleton::the_one = new Singleton();
COSC346 - Pattern of the Day - Lecture 7
25
Prototype
Problem:How to make new objects when we don’t know the type of object at compile time.
Solution: Pass in a prototype variable to the appropriate method (using a parent class) and clone that prototype.
COSC346 - Pattern of the Day - Lecture 7
26
Exampleclass Building {private:Wall *wallPrototype;map<Location *, Wall *> walls;public: public Building(Wall *_wallPrototype) { wallPrototype = _wallPrototype;};
void addWall(Location *l) {walls[l] = wallPrototype.clone();};
}
COSC346 - Pattern of the Day - Lecture 7
27
Example
Building *house = new Building(new BrickWall());
house->addWall(East);
house->addWall(West);
Building glassHouse = new Building(new GlassWall());
glassHouse->addWall(East);
Building shed = new Building(new CorrugatedIronWall());
COSC346 - Pattern of the Day - Lecture 7
28
Example Modified
class Building {
public:
Building(Wall *wallPrototype) {
addWall(East, wallPrototype.clone());
addWall(West, wallPrototype.clone());
addWall(North, wallPrototype.clone());
addWall(South, wallPrototype.clone());
}
}
COSC346 - Pattern of the Day - Lecture 7
29
Consequences
• Reduced subclassing.
• Dynamic composition.
• Requires a clone method.
Adapter/Facade/Proxy
• Three very similar design patterns that use intermediary classes between client and workers.
• Adapter: converts an interface to a subsystem interface a client requires.
• Facade: defines an interface (with several workers) that makes the subsystem easier to use.
• Proxy: acts as a placeholder for another object to control access to it.
Adapter
Client Adapter Adaptee
Facade
FacadeClient
Worker 1
Worker 2
Worker 3
Proxy
Client Proxy Server