cse 332: design patterns introduction to design patterns you’ve seen design patterns several times...

19

Click here to load reader

Upload: solomon-singleton

Post on 08-Jan-2018

216 views

Category:

Documents


0 download

DESCRIPTION

CSE 332: Design Patterns Pattern-Oriented Design We’ll start by outlining a simple design exercise (Part I) –Idea: maintain a portfolio of stocks and bonds –Design goals Traverse the portfolio and print out each element Print out the portfolio in different orders Provide a common interface to a single portfolio instance Calculate current and projected values of the portfolio We’ll see how key patterns drive the design (Part II) –Iterator: access elements sequentially no matter how stored –Factory method: create a related type polymorphically –Singleton: provides access to a single instance –Strategy: makes behaviors pluggable via common interfaces –Adapter: converts an interface you have into one you want –Visitor: allows interaction with heterogeneous collections We’ll talk about how we’ve evolved a pattern language (Part III) –Can be reused different design settings where the same issues arise

TRANSCRIPT

Page 1: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Introduction to Design Patterns• You’ve seen design patterns several times this semester

– The Iterator pattern has been discussed in some detail (STL lectures)– We’ve also seen the Factory Method pattern (but haven’t named it yet)

• This lecture will focus on design patterns in detail– What they are and how they are structured (in detail)– Introduction to some of important design patterns (from Gamma et al.)

• We’ll work through a design exercise step by step– Each time we come to a design problem we’ll introduce a design pattern– We’ll see how the pattern resolves the problem

• Next lecture we’ll talk about how to combine sets of patterns– Create “design pattern languages” that also can be reused – Today’s patterns form a pattern language, though we won’t consider them in that

way until we’ve reached the end of the design exercise

Page 2: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

What’s a Design Pattern?• A design pattern has a name

– So when someone says “Adapter” you know what they mean– So you can communicate design ideas as a “vocabulary”

• A design pattern describes the core of a solution to a recurring design problem– So you don’t have to reinvent known design techniques– So you can benefit from others’ (and your) prior experience

• A design pattern is capable of generating many distinct design decisions in different circumstances– So you can apply the pattern repeatedly as appropriate– So you can work through different design problems using it

Page 3: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Pattern-Oriented Design• We’ll start by outlining a simple design exercise (Part I)

– Idea: maintain a portfolio of stocks and bonds– Design goals

• Traverse the portfolio and print out each element• Print out the portfolio in different orders• Provide a common interface to a single portfolio instance• Calculate current and projected values of the portfolio

• We’ll see how key patterns drive the design (Part II)– Iterator: access elements sequentially no matter how stored– Factory method: create a related type polymorphically– Singleton: provides access to a single instance– Strategy: makes behaviors pluggable via common interfaces– Adapter: converts an interface you have into one you want– Visitor: allows interaction with heterogeneous collections

• We’ll talk about how we’ve evolved a pattern language (Part III)– Can be reused different design settings where the same issues arise

Page 4: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Part I: Design Exercise Outline• Idea: keep track of a portfolio of stocks and bonds

– Abstractly, both stocks and bonds are securities• Each has a name, a number of shares, a current value, and a

projected value

– Stocks and bonds are distinct abstractions, however• Stocks can have a dividend that’s paid out periodically• Bonds can earn interest that’s also paid out periodically

• Design goals– Traverse the portfolio and print out each element– Print out the portfolio in different orders– Provide a common interface to a single portfolio instance– Calculate current and projected values of the portfolio

Page 5: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Basic Abstractions: Security, Stock, Bondstruct Security { Security (char * name, int shares, int current_value, int projected_value); virtual ~Security ();

char * name_; int shares_; int current_value_; int projected_value_;};

struct Stock: public Security {  Stock (char * name, int shares, int current_value, int projected_value, int dividend); virtual ~Stock ();  

int dividend_;};

struct Bond: public Security { Bond (char * name, int shares, int current_value, int projected_value, int interest); virtual ~Bond ();  int interest_;};

Page 6: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Portfolio Abstraction: A Collection of Securitiesclass Portfolio {  public:  enum error_condition {not_found = 1, already_there};

Portfolio (); virtual ~Portfolio (); void add (Security *); // takes ownership void remove (Security *); // releases ownership void print (); int current_value ();  int projected_value ();   private:  deque<Security *> securities_;

// prevent copy construction, assignment  Portfolio (const Portfolio &); Portfolio & operator= (const Portfolio &);};

Page 7: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Part II: Applying Patterns to the Design

• Now we’ll look at how key patterns drive the design forward– Iterator: access elements sequentially no matter how stored– Factory method: create a related type polymorphically– Singleton: provides access to a single instance– Strategy: makes behaviors pluggable via common interfaces– Adapter: converts an interface you have into one you want– Visitor: allows interaction with heterogeneous collections

• Our first challenge is how to iterate through the collection of securities in the portfolio so that we can print out its contents– Motivates use of the Iterator pattern here, in ways that should be familiar– Motivates use of the Factory Method pattern, also in familiar ways

• We’ll look at each of these patterns first• Then we’ll look at code that takes advantage of them

Page 8: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Iterator Pattern• Problem

– Want to access aggregated elements sequentially• E.g., traverse a container of securities and print them out

• Context– Don’t want to know/manage details of how they’re stored

• E.g., could be in a list or an array, but in fact they’re kept in a deque (nicely balances ease of sorting, iteration, addition, and erasure)

• Solution core– Provide an interface for iteration over each container

• Consequences– Frees user from knowing details of how elements are stored– Decouples containers from algorithms (crucial in C++ STL)

• Other examples we’ve seen before– C++ pointers, C++ STL list<int>::iterator

Page 9: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Factory Method Pattern• Problem

– You want a type to create another related type polymorphically– E.g., a container should create appropriate begin and end iterators

• Context– Each type knows which related type it should create

• Solution core– Polymorphic creation– E.g., declare abstract method that derived classes override– E.g., provide traits and common interface as in the STL (what we’ll use)

• Consequences– Type that’s created matches type(s) it’s used with– E.g., appropriately positioned deque<Security *>::iterators are

produced by the deque<Security *> begin() and end() methods

Page 10: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Basic Use of Iterator, Factory Method Patternsvoid Portfolio::print () { for (deque<Security *>::iterator i = securities_.begin(); i != securities_.end(); ++i) {

cout << (*i)->shares_ << " shares of " << (*i)->name_ << " currently at " << (*i)->current_value_ << " and projected to be " << (*i)->projected_value_ << endl; } 

cout << "Current portfolio value: " << current_value() << endl; cout << "Projected portfolio value: " << projected_value() << endl;

}• Now onto the next design challenges we’ll address

– Only need a single portfolio instance, want easy access to it– We’ll see how the Singleton pattern helps with this

– Want to sort the portfolio in different ways before printing it– We’ll see how the Strategy and Adapter patterns help with this

Page 11: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Singleton Pattern• Problem

– Want to ensure a single instance of a class, that’s shared by all uses throughout a program (e.g., the Portfolio)

• Context– Need to address initialization versus usage ordering

• Solution core– Provide a global access method (static member function)– First use of the access method instantiates the class– Constructors for instance can be hidden (made private)– Can hide destructor too if a “fini” method is also provided

• Consequences– Object is never created if it’s never used– Object is shared efficiently among all uses

Page 12: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Basic Use of the Singleton Patternclass Portfolio { public: static Portfolio * instance(); static void fini();  … private:  static Portfolio * instance_;  Portfolio (); virtual ~Portfolio (); …};

Portfolio * Portfolio::instance_ = 0;Portfolio * Portfolio::instance() { if (instance_ == 0){ instance_ = new Portfolio; } return instance_;}void Portfolio::fini() { delete instance_; instance_ = 0;}

int main (int, char * []) {  try {  Bond *b = new Bond ("City Infrastructure", 10, 2, 3, 5); Stock *s = new Stock ("Alice's Restaurant", 20, 7, 11, 13); Portfolio::instance()->add (b); Portfolio::instance()->add (s); Portfolio::instance()->print (); Portfolio::fini(); } catch (Portfolio::error_condition &e) { cout << "Portfolio error: " << e << endl; return -1; } catch (...) { cout << "unknown error" << endl; return -2; }  return 0;}

Page 13: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Strategy Pattern• Problem

– Want to plug in a family of alternative parameters to modify behavior (e.g., for sorting the securities before printing them)

• Context– Need a common interface for the family of parameters (e.g.,

less, greater, plus any parameters we want to define)– Need polymorphic substitution of parameter objects

• Solution core– Give the different parameter objects a common interface– Plug these strategies in to modify other behavior (e.g., sort)

• Consequences– Behavior of algorithms (etc.) is easily modified– Can extend family of parameters as needed (see example)

Page 14: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

(Attempted) Basic Use of the Strategy Pattern

struct PrintOrderFunctor { virtual ~PrintOrderFunctor (); virtual bool operator () (Security * lhs, Security * rhs) const = 0; };

void Portfolio::print (PrintOrderFunctor * ppof) {  if (ppof) { sort (securities_.begin(), securities_.end(), *ppof); }…} 

• We’d like to have something like the code below– Although the top part works, the bottom part doesn’t– STL algorithms take arguments by value (class slicing)– Can’t instantiate PrintOrderFunctor due to pure virtual

• Needs a better way to use the abstract base class

Page 15: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Adapter Pattern• Problem

– We have an interface that’s close to (but not exactly) what we need (cannot use it “as is”)

• Context– Want to re-use an existing class– Can’t change its interface – Impractical to extend class hierarchy more generally

• Solution core– Wrap the interface we have with the interface we need

• Consequences– For a bit more effort, get reuse of what you started with

Page 16: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Basic Use of the Adapter Patternstruct PrintOrderFunctor { virtual ~PrintOrderFunctor (); virtual bool operator () (Security * lhs, Security * rhs) const = 0; };

struct PrintOrderFunctorAdapter { PrintOrderFunctor &pof_; PrintOrderFunctorAdapter (PrintOrderFunctor &pof) : pof_(pof) {} bool operator () (Security * lhs, Security * rhs) {return pof_(lhs, rhs);}};

void Portfolio::print (PrintOrderFunctor * ppof) { if (ppof) {PrintOrderFunctorAdapter pofa (*ppof); sort (securities_.begin(), securities_.end(), pofa);}…} 

• One last design challenge (at least for today)– How can we calculate the projected value of the portfolio?

– Need to consider either stock dividend or bond interest– How can we know which is which when traversing the securities?

Page 17: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Visitor Pattern• Problem

– We have a heterogeneous collection of objects over which we need to perform type-specific operations

• Context– Run-time type identification adds overhead and complexity– Want to avoid unnecessary interactions among types – Types in collection change less frequently than the set of

operations that are to be performed over them• Solution core

– Modify types in the collection to support double dispatch• Consequences

– Once modified in this way, any of the types can handshake with arbitrary “visitors” to give correct behavior

Page 18: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Basic Use of the Visitor Patternstruct SecurityVisitor { virtual ~SecurityVisitor(); virtual void visit_stock (Stock *) = 0; virtual void visit_bond (Bond *) = 0;};

struct Security { … virtual void accept (SecurityVisitor * sv) = 0;};

void Stock::accept (SecurityVisitor * sv) { if (sv) {sv->visit_stock(this);}}

void Bond::accept (SecurityVisitor * sv) { if (sv) {sv->visit_bond(this);}}

struct ProjectedValueFunctor : public SecurityVisitor { int & value_; ProjectedValueFunctor (int & value); virtual ~ProjectedValueFunctor (); void operator () (Security * s) { s->accept(this); } virtual void visit_stock (Stock * s) { if (s) {value_ += s->shares_ * (s->projected_value_ + s->dividend_);} } virtual void visit_bond (Bond * b) { if (b) {value_ += b->shares_ * (b->projected_value_ + b->interest_);} }};

int Portfolio::projected_value () { int value = 0; for_each (securities_.begin(), securities_.end(), ProjectedValueFunctor(value)); return value;}

Page 19: CSE 332: Design Patterns Introduction to Design Patterns You’ve seen design patterns several times this semester –The Iterator pattern has been discussed

CSE 332: Design Patterns

Part III: A Design Pattern Language• We’ve now evolved what’s called a “pattern language”

– A recurring sequence of design patterns that can be applied to solve a recurring sequence of design challenges each time you see it

– To identify such pattern languages, look for repetition not only of individual patterns, but also of combinations and sequences of patterns

– Then, look for repetition of the design problems, and apply the language

• This pattern language can be reused when same issues arise– E.g., any design involving a single collection of heterogeneous elements– E.g., instead of a portfolio of stocks and bonds, a zoo of zebras and birds

• Next lecture we’ll evolve another design pattern language– To address additional challenges raised by multiple interacting agents– We’ll apply the pattern language to further extend today’s design– We’ll add multiple agents, each with their own portfolio– We’ll add (closed agent-to-agent) cross trading of securities among them– We’ll add a market to mediate event triggered open trading of securities