02 Behavioral Design Patterns 1 Moshe Fresko BarIlan
02 - Behavioral Design Patterns – 1 Moshe Fresko Bar-Ilan University תשס"ח 2008
Behavioral Patterns l l l Behavioral Patterns are concerned with algorithms and the assignment of responsibilities between objects. Not only patterns of objects/classes but also patterns of communication between them. These patterns are: l l l l l Template Method: An abstract definition of an algorithm. Interpreter: Represents a grammar as a class hierarchy and implements an interpreter as an operation on instances of these classes. Mediator: Provides the indirection needed for loose coupling. Chain of Responsibility: Lets you send requests to an object implicitly through a chain of candidate objects. Observer: Defines and Maintains dependency between objects. (MVC) Strategy: Encapsulates an algorithm in an Object. Command: Encapsulates a request in an Object. State: Encapsulates the states of an Object so that the Object can change its behavior when its state object is changes. Visitor: Encapsulates behavior that would otherwise be distributed across classes. Iterator: Abstracts the way you access and traverse objects in an aggregate.
Iterator Moshe Fresko Bar-Ilan University תשס"ו - 2005 -2006 Design Patterns Course
Iterator l Intent l l Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation. Motivation l l l An aggregate object such as a list should give you a way to access its elements without exposing its internal structure. Moreover you might want to traverse the list in different ways. We cannot fill the List interface with different traversals we can need. We may want a couple of traversals pending on the same time.
Iterator
Iterator – Example Structure
Iterator l Use iterator pattern … To access an aggregate object’s contents without exposing its internal representation. l To support multiple traversals of aggregate objects. l To provide a uniform interface for traversing different aggregate structures (to support polymorphic iteration). l
Iterator – General Structure
Iterator l Participants l l Iterator l Defines an interface for accessing and traversing elements Concrete. Iterator l Implements the iterator interface l Keeps track of the current position in the traversal Aggregate l Defines an interface method that creates an iterator object Concrete. Aggregate l Implements the iterator creation method, and returns an instance of the proper Concrete. Iterator
Iterator l l Consequences l It supports variants in the traversal of an aggregate l Iterators simplify the Aggregate interface l More then one traversal can be pending on an aggregate Implementation l Who controls the iteration? l l l Who defines the traversal algorithm? l l l External Iterator: Client controls the iteration Internal Iterator: The Iterator controls the iteration The aggregate: This is called a cursor. The iterator. How robust is the iterator? l l Modifying an aggregate while traversing it will be dangerous for iterator. Robust iterator will not be effected by changes.
Java Iterators interface Collection { … Iterator iterator(); … } Interface Iterator { boolean has. Next() ; Object next() ; void remove() ; } interface Set extends Collection { … Iterator iterator(); … } Interface List. Iterator extends Iterator { boolean has. Next() ; Object next() ; boolean has. Previous() ; Object previous() ; int next. Index() ; int previous. Index() ; void remove() ; void set(Object o) ; void add(Object o) ; } interface List extends Collection { … Iterator iterator(); List. Iterator list. Iterator(int index); … }
Java Iterator import java. util. *; public class Iterator. Example { public static void main(String[] args) { List ints = new Array. List(); for(int i = 0; i < 10; i++) ints. add(new Integer(i)); Iterator e = ints. iterator(); while(e. has. Next()) System. out. println( ((Integer)e. next()). int. Value() ) ; } }
Chain of Responsibility Moshe Fresko Bar-Ilan University תשס"ו - 2005 -2006 Design Patterns Course
Chain of Responsibility l Use Chain of Responsibility when … l l l More then one object may handle a request, and the handler isn’t known a-priori. You want to issue a request to one of several objects without specifying the receiver explicitly. The set of objects that handle a request should be specified dynamically.
Chain of Responsibility General Structure
Chain of Responsibility l Participants l l l Handler (Help. Handler) l Defines and interface for handling requests. l Implements the successor link. Concrete. Handler (Print. Button, Print. Dialog) l Handles requests it is responsible for. l Can access its successor. l If it does not handle the request, then it forwards it to its successor. Client l Initiates the request to a Concrete. Handler object on the chain.
Chain of Responsibility l Consequences l l Reduced Coupling Flexibility in assigning responsibilities to Objects Receipt isn’t guaranteed. Implementation l l Implementing the successor chain can be done with a new implementation or use existing links. Representing Requests may be via an object.
Chain of Responsibility // Chain with a new implementation class Help. Handler { private Help. Handler successor = null ; Help. Handler(Help. Handler successor) { this. successor = successor ; } public void handle. Help() { if (successor!=null) { successor. handle. Help() ; } } } // Any relationship (hierarchical or list) like is-a can be used for chaining
Interpreter Moshe Fresko Bar-Ilan University תשס"ו - 2005 -2006 Design Patterns Course
Interpreter l Intent l l Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language. Motivation l l If a particular kind of problem occurs often enough, then it might be worthwhile to express instances of the problem as sentences in a simple language. For example: l Regular Expressions l Document Retrieval Query
Interpreter Regular Expression Example l A simple Regular Expression Grammar expression : : = literal | alternation | sequence | repetition | ‘(’ expression ‘)’ alternation : : = expression ‘|’ expression sequence : : = expression ‘&’ expression repetition : : = expression ‘*’ literal : : = ‘a’ | ‘b’ | ‘c’ | … { ‘a’ | ‘b’ | ‘c’ | … } *
Interpreter – Example Structure
Interpreter – Possible Structure
Interpreter l Applicability l l Use Interpreter pattern when there is a language to interpret, and you can represent statements in the language as abstract syntax trees. The interpreter works well, when The grammar is simple l Efficiency is not a critical concern l
Interpreter – General Structure
Interpreter l Participants l Abstract. Expression (Regular. Expression) l l Terminal. Expression (Literal. Expression) l l l Keeps Abstract. Expression for each internal symbol it keeps Implements interpret() operation. Context l l Implements the interpret() operation for terminal symbols in the grammar Nonterminal. Expression (Alternation. Expression, Repetition. Expression, Sequence. Expression) l l Declares an abstract interpret() operation Contains information that is global to the interpreter Client l l Builds the abstract syntax tree Calls the interpret() operation
Interpreter l Consequences l l It is easy to change and extend the grammar Implementing the grammar is easy Complex grammars are hard to maintain Implementation l l l Creating the abstract syntax tree Defining the interpret() operation Sharing terminal symbols with the Flyweight pattern
Interpreter – Example l Grammar for Document Search expression : : = literal | alternation | intersection alternation : : = expression OR expression intersection : : = expression AND expression literal : : = ‘a’|‘b’|‘c’|… literal : : = literal ‘a’|‘b’|‘c’…
Interpreter – Example // Interface of a document collection interface Doc. Collection { int[] get. Doc. Numbers. For. Word(String word) ; } // Interface for searching a document colletion interface Doc. Search { int[] get. Doc. Numbers(Doc. Collection d) ; } // A Literal search class Literal implements Doc. Search { String word ; Literal(String word) { this. word = word ; } public int[] get. Doc. Numbers(Doc. Collection d) { return d. get. Doc. Numbers. For. Word(this. word) ; } }
Interpreter – Example // An alternation search class Alternation implements Doc. Search { Doc. Search search 1=null ; Doc. Search search 2=null ; Alternation(Doc. Search search 1, Doc. Search search 2) { this. search 1=search 1; this. search 2=search 2; } public int[] get. Doc. Numbers(Doc. Collection d) { return Utils. union(search 1. get. Doc. Numbers(d), search 2. get. Doc. Numbers(d)) ; } } // An intersection search class Intersection implements Doc. Search { Doc. Search search 1=null ; Doc. Search search 2=null ; Intersection(Doc. Search search 1, Doc. Search search 2) { this. search 1=search 1; this. search 2=search 2; } public int[] get. Doc. Numbers(Doc. Collection d) { return Utils. intersection(search 1. get. Doc. Numbers(d), search 2. get. Doc. Numbers(d)) ; } }
Interpreter – Example // The factory for creating the interpreted Doc. Search pointer class Doc. Search. Interpreter { public static Doc. Search interpret(String query) { String[] alt = query. split(" OR ") ; Doc. Search d = interpret. And(alt[0]) ; for (int i=1; i<alt. length; ++i) d = new Alternation(d, interpret. And(alt[i])) ; return d ; } private static Doc. Search interpret. And(String query) { String[] alt = query. split(" AND ") ; Doc. Search d = interpret. One(alt[0]) ; for (int i=1; i<alt. length; ++i) d = new Intersection(d, interpret. One(alt[i])) ; return d ; } private static Doc. Search interpret. One(String query) { return new Literal(query. trim()) ; } }
Interpreter – Example // Some utilities for union and // intersection of sorted integer lists class Utils { public static int[] union(int[] a, int[] b) { List l = new Array. List() ; int i=0, j=0; while (i<a. length && j<b. length) { if (a[i]==b[j]) { l. add(new Integer(a[i])) ; i++ ; j++ ; continue ; } else if (a[i]<b[j]) { l. add(new Integer(a[i])) ; i++ ; continue ; } else { l. add(new Integer(b[j])) ; j++ ; continue ; } } for (; i<a. length; ++i) l. add(new Integer(a[i])) ; for (; j<b. length; ++j) l. add(new Integer(b[j])) ; return array. From. List(l) ; } public static int[] intersection(int[] a, int[] b) { List l = new Array. List() ; int i=0, j=0; while (i<a. length && j<b. length) { if (a[i]==b[j]) { l. add(new Integer(a[i])) ; i++ ; j++ ; continue ; } else if (a[i]<b[j]) { i++ ; continue ; } else { j++ ; continue ; } } return array. From. List(l) ; } private static int[] array. From. List(List l) { int[] r=new int[l. size()] ; for (int i=0; i<r. length; ++i) r[i]=((Integer)l. get(i)). int. Value() ; return r ; } }
Command Moshe Fresko Bar-Ilan University תשס"ו - 2005 -2006 Design Patterns Course
Command Pattern l l Intent: Encapsulate a request as an Object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. Motivation: l The Command Pattern lets toolkit objects make requests of unspecified application objects by turning the request itself into an Object. This object can be stored and passed around.
Command - Motivation l Menus can be implemented easily. Each choice in a Menu instance is an instance of Menu. Item class.
Command – Motivation
Command – Motivation
Command – Motivation
Command – Applicability l Use Command pattern when you want to l l l Parametrize objects by an action to perform. (callback function or Interface) Specify, queue and execute requests at different times. Support undo. Support logging. Structure a system around high-level operations built on primitive operations.
Command – Structure
Command – Participants l l l Command l Declares an interface for executing an operation. Concrete. Command l Defines a binding between a receiver object and an action. l Implements Execute by invoking the corresponding operations on Receiver. Client l Creates a Concrete. Command object and sets its receiver. Invoker l Asks the Command to carry out the request. Receiver l Knows how to perform the operations associated with carrying out a request.
Command – Interactions
Command – Consequences l l Command decouples the object that invokes the operation from the one that knows how to perform it. Commands are first-class objects. They can be manipulated and extended. You can assemble commands into a composite command. It's easy to add new Commands, because you don't have to change existing classes.
Command – Implementation l l How intelligent should a Command be? Supporting undo and redo. Avoiding error accumulation in the undo process. Using C++ templates to avoid creating a Command subclass for every kind of action and receiver.
Command – Sample Code class Command { public: virtual ~Command(); virtual void Execute() = 0; protected: Command(); };
Command – Sample Code class Open. Command : public Command { private: Application* _application; char* _response; public: Open. Command(Application*) { _application = a; } virtual void Execute() { const char* name = Ask. User(); Document* document = new Document(name); _application->Add(document); document->Open(); } protected: virtual const char* Ask. User(); };
Command – Sample Code class Paste. Command : public Command { private: Document* _document; public: Paste. Command(Document*) { _document = doc; } virtual void Execute() { _document->Paste(); } };
Command – Sample Code template <class Receiver> class Simple. Command : public Command { public: typedef void (Receiver: : * Action)(); Simple. Command(Receiver* r, Action a) : _receiver(r), _action(a) { } virtual void Execute() { (_receiver->*_action)(); } private: Action _action; Receiver* _receiver; };
Command – Sample Code My. Class* receiver = new My. Class; //. . . Command* a. Command = new Simple. Command<My. Class> (receiver, &My. Class: : Action); //. . . a. Command->Execute();
Command – Sample Code class Macro. Command : public Command { private: List<Command*>* _cmds; public: Macro. Command(); virtual ~Macro. Command(); virtual void Add(Command*) { _cmds->Append(c); } virtual void Remove(Command*) { _cmds->Remove(c); } virtual void Execute() { List. Iterator<Command*> i(_cmds); for (i. First(); !i. Is. Done(); i. Next()) { Command* c = i. Current. Item(); c->Execute(); } } };
- Slides: 50