CS 247: Software Engineering Principles Design Patterns Reading: Freeman, Robson, Bates, Sierra, Head First Design Patterns, O'Reilly Media, Inc. 2004 Ch Strategy Pattern Ch 7 Adapter and Facade patterns Ch 8 Template Method Design Patterns CS240 covers data structure patterns: priority queue AVL tree B-tree CS34 covers algorithm patterns: divide and conquer greedy dynamic programming CS247 covers OO patterns that encapsulate design decisions that might change. These are all patterns that good programmers know. U Waterloo CS247 (Spring 207) p./29 U Waterloo CS247 (Spring 207) p.2/29 "Gang of Four"* Design Patterns Abstract OO designs that encapsulate change, to improve the modularity and flexibility of our code. i.e., increase cohesion, loosen coupling, improve information hiding How patterns help: Improve our efficiency in finding a suitable design Improve the predictability of the design quality Offer higher-level abstractions than procedures or classes Extend developers' vocabulary Ease refactoring and evolution *GoF = "Gang of Four", authors of original book on object-oriented Design Patterns U Waterloo CS247 (Spring 207) p.3/29 Purpose Creational Structural Behavioural "Gang of Four" Design Patterns OO design patterns encapsulate some design decision that might change. Design Pattern Abstract Factory Builder Factory Method Prototype Singleton Adapter Bridge Composite Decorator Facade Flyweight Proxy Chain of Responsibility Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor Aspect(s) That Can Vary families of product objects how a composite objects gets created subclass of object that is instantiated class of object that is instantiated the sole instance of a class interface to an object implementation of an object structure and composition of an object responsibilities of an object without subclassing interface to a subsystem storage costs of objects how an object is accessed; its location object that can fulfill a request when and how a request is fulfilled grammar and interpretation of a language how an aggregate's elements are accessed, traversed how and which objects interact with each other what private information is stored outside an object, and when objects that depend on another object; how the dependent objects stay up to date states of an object an algorithm steps of an algorithm operations that can be applied to objects(s) without changing their class(es) Gamma, Helm, Johnson, Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 995 (p.30) U Waterloo CS247 (Spring 207) p.4/29
Examples from SE_203: References Gamma, Helm, Johnson, Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 994. Freeman and Freeman, Head First Design Patterns, O'Reilly, 2004. Code examples: http://headfirstlabs.com/books/hfdp/ http://www.student.cs.uwaterloo.ca/~cs247/current/patterns.shtml U Waterloo CS247 (Spring 207) p.5/29 Problem: Duplicate Code Consider a bicycle computer that has a mode button for switching the display of different data being collected: current time, speed, distance Time hour min sec display Display setlabel (string) setunits (string) setvalue (string) display Speed speed display Distance dist U Waterloo CS247 (Spring 207) p.6/29 Similar Algorithms void Distance::showValue () { display_.setlabel ("D"); display_.setvalue (dist_); display_.setunits ("km"); void Time::showValue () { display_.setlabel ("T"); display_.setvalue (hour_ + ":" + min_ + ":" + sec_); display_.setunits ( "" ); void Speed::showValue () { display_.setlabel ("S"); display_.setvalue (speed_); display_.setunits ("km/h"); U Waterloo CS247 (Spring 207) p.7/29 Display setlabel (string) setunits (string) setvalue (string) Approach : Inheritance display Time hour min sec Function Speed speed Put common code in abstract base class's method. Can be shared by subclasses' methods. Position dist Downside: subclasses may neglect to use parent behaviour. U Waterloo CS247 (Spring 207) p.8/29
Inheriting Common Code void Function::showValue () { display_.setlabel (XXX); display_.setvalue (YYY); display_.setunits (ZZZ); The commonality among the classes' methods is the structure of the algorithm. The variations are data values (but the data values could just as easily be subroutine values). Approach 2: Template Method A template method is a base-class method that defines common code structure, but includes primitive operations (holes) to be defined by subclass methods. void Function::showValue (){ display_.setlabel ( thelabel() ); display_.setvalue ( thevalue() ); display_.setunits ( theunits() ); // pure virtual methods Derived classes override holes than override entire method virtual std::string Function::theLabel () = 0; virtual std::string Function::theValue () = 0; virtual std::string Function::theUnits () = 0; It is essential that: the template method be nonvirtual the primitive operations be virtual functions in the base class U Waterloo CS247 (Spring 207) p.9/29 U Waterloo CS247 (Spring 207) p.0/29 Function + - thelabel() - thevalue() - theunits() Distance dist - thelabel() - thevalue() - theunits() Template Method // template method void Function::showValue () { display_.setlabel ( thelabel() ); display_.setvalue ( thevalue() ); display_.setunits ( theunits() ); // primitive operations virtual std::string Function::theLabel() = 0; virtual std::string Function::theValue() = 0; virtual std::string Function::theUnits() = 0; string Distance::theLabel() override { return string("d"); string Distance::theValue() override { return string(dist_); string Distance::theUnits() override { return string("km"); U Waterloo CS247 (Spring 207) p./29 Template Method Pattern Problem: duplicate code Multiple subclass methods have similar algorithm structures. Solution: localize duplicate code structure in an abstract class Abstract class defines a template method (of common code) that calls pure virtual subroutines. Subclasses override the subroutines. Client AbstractClass TemplateMethod() PrimitiveOperation() PrimitiveOperation2() ConcreteClass PrimitiveOperation() PrimitiveOperation2() concrete primitive operations concrete template method abstract primitive operations ConcreteClass2 PrimitiveOperation() PrimitiveOperation2() U Waterloo CS247 (Spring 207) p.2/29
Example: Assignment Operation that bills a cellphone plan subscriber, based on plan type: - monthly fee - charges for additional calls Account balance + bill ( ) monthlyfee ( ) callcharges ( ) concrete template method abstract virtual primitive operations Abstract Account class Account { Account (); void bill ();... int balance_; virtual int monthlyfee() = 0; virtual int callcharges() = 0; ; CheapAccount int monthlyfee int numfreemin int ratepercall int monthlyfee ( ) int callcharges ( ) concrete primitive operations ExpensiveAccount int monthlyfee int monthlyfee ( ) int callcharges ( ) Account::Account(): balance_{0 { // template method void Account::bill() { balance_ += monthlyfee() + callcharges(); U Waterloo CS247 (Spring 207) p.3/29 U Waterloo CS247 (Spring 207) p.4/29 CheapAccount class CheapAccount : public Account { CheapAccount ( ); static const int monthlyfee_ = 25; static const int freemin_ = 250; static const int rate_ = ; int minutes_; int monthlyfee() override; int callcharges() override; ; CheapAccount::CheapAccount: minutes_{0 { int CheapAccount::monthlyFee() { return monthlyfee_; int CheapAccount::callCharges() { if ( (minutes_ - freemin_) > 0 ) return (minutes_ - freemin_) * rate_; return 0; U Waterloo CS247 (Spring 207) p.5/29 ExpensiveAccount class ExpensiveAccount : public Account { ExpensiveAccount ( ); static const int monthlyfee_ = 80; int monthlyfee() override; int callcharges() override; ; ExpensiveAccount:ExpensiveAccount( ) { int ExpensiveAccount::monthlyFee () { return monthlyfee_; int ExpensiveAccount::callCharges() { return 0; U Waterloo CS247 (Spring 207) p.6/29
Adapter Pattern Idea Problem: Interface mismatch between two modules. Want to reuse an existing class, but its interface does not match what is needed. Or the interface of one of our modules changes (!!) and we don't want to make major changes to the existing (working!) code. Solution: Define an Adapter class that maps one interface to another. Example: STL Stacks STL stacks are implemented by adapting the interface of a Container class (by default, deque). stack<t> push(t) pop() top() : T empty() : bool size() : int contents Container<T> empty() : bool size() : int back() : T push_back(t) pop_back() Client Adapter Existing code deque<t> vector<t> list<t> U Waterloo CS247 (Spring 207) p.7/29 U Waterloo CS247 (Spring 207) p.8/29 STL Stacks Here is a version of the implementation: template<typename T, template<typename,typename> class Container = std::deque, class A = std::allocator<t>> class stack { bool empty() const; int size() const; T& top() const; void push(const T& val); void pop(); Container<T> contents_; ; template<typename T, template<typename,typename> class C, class A> void stack::push(const T& val) {contents_.push_back(val); Adapter Pattern (object adapters) The Adapter class translates requests made to the Target interface into requests made of the Adaptee object. Client Target request() Adapter request() adaptee..* Adaptee realrequest() adaptation template<typename T, template<typename,typename> class C, class A> void stack::pop() { contents_.pop_back(); U Waterloo CS247 (Spring 207) p.9/29 adaptee->realrequest(); U Waterloo CS247 (Spring 207) p.20/29
Facade Design Pattern Metaphor: Facade Design Pattern Problem: complex interface. Client of subsystem interacts with multiple (complex?) classes. Solution: create a single, simplified interface (class). Restrict, simplify client's interactions with subsystem's classes. client classes FACADE subsystem classes U Waterloo CS247 (Spring 207) p.2/29 U Waterloo CS247 (Spring 207) p.22/29 Another Example Strategy Pattern Problem: Want to vary an algorithm at run-time. GUI Solution: Encapsulate the algorithm decision. Define algorithm as a component object. Use subclassing to specialize the algorithm in different ways. Controller GamePlay Player Card Deck backend of game Context performalgorithm() Strategy strategy algorithm() ConcreteStrategy algorithm() ConcreteStrategy2 algorithm() ConcreteStrategy3 algorithm() GameBoard U Waterloo CS247 (Spring 207) p.23/29 U Waterloo CS247 (Spring 207) p.24/29
Example A class that authenticates users, and uses a variety of authentication policies. Example 2 A card player whose strategy changes at runtime. UserSession authenticate() authpolicy AuthenticationPolicy authenticate(... ) AgilePlayer bid ( ) strategy BiddingStrategy bid( AgilePlayer ) Password authenticate(... ) Challenge-Handshake authenticate(... ) Public/Private Keys authenticate(... ) Conservative bid( AgilePlayer ) Aggressive bid( AgilePlayer ) U Waterloo CS247 (Spring 207) p.25/29 U Waterloo CS247 (Spring 207) p.26/29 Implementation class AgilePlayer { BiddingStrategy *strategy_;... AgilePlayer();... void bid ( ); void reassess_bidding_strategy( ); ; AgilePlayer::AgilePlayer() : strategy_{new Conservative { Considerations Applicability: Different variants of an algorithm. Choose/Change algorithm at runtime. Some complications: Encapsulation of context data to be operated on. All algorithms must use the same Strategy interface. void AgilePlayer::bid( ) { strategy_->bid(*this); void AgilePlayer::reassess_Bidding_Strategy( ) {... // decide to change bidding strategy delete strategy_; strategy_ = new Aggressive; U Waterloo CS247 (Spring 207) p.27/29 U Waterloo CS247 (Spring 207) p.28/29
Summary The goal of design patterns is to encapsulate change. Template Method Pattern: encapsulates that parts of an algorithm that is different for each derived class. Adapter Pattern: encapsulates the interface to a class. Facade Pattern: doesn t really encapsulate the subsystem classes since they re still available but does decouple the client from the subsystem. Strategy Pattern: encapsulates the algorithm to be used, such that it can be set (and changed) at runtime. U Waterloo CS247 (Spring 207) p.29/29