Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects.Behavioral patterns describe not just patterns of objects or classes but also the patterns of communication between them.These patterns characterize complex control flow that’s difficult to follow at run-time.They shift your focus away from flow of control to let you concentrate just on the way objects are interconnected.
*Behavioral class patterns use inheritance to distribute behavior between classes.
*Behavioral object patterns use object composition rather than inheritance.
I.Chain of responsibility
Intent:
Avoid couping the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.
To forward the request along the chain,and to ensure receivers remain implicit,each object on the chain shares a common interface for handling requests and for accessing its successor on the chain.
Applicability:Use Chain of Responsibility when:
*more than one object may handle a request,and the handler isn’t known a priori.The handler should be ascertained automatically.
*you want to issue a request to one of several objects without specifying the receiver explicitly.
*the set of objects that can handle a request should be specified dynamically.
Structure:
Consequences:Chain of Responsibility has the following benefits and liabilities:
*Reduced coupling.The pattern frees an object fom knowing which other object handles a request.
*Added flexibility in assigning responsibilities to objects.You can add or change responsibilities for handling a request by adding to or otherwise changing the chain at run-time.
*Receipt isn’t guaranted.The request can fall off the end of the chain without ever being handled.
Implementation:
*Implementing the successor chain.
(a)Define new links(usually in the Handler,but ConcreteHandlers could define them instead)
(b)Use existing links.
*Connecting successors.
Here’s a HelpHandler base class that maintains a successor link:
class HelpHandler{
public:
HelpHandler(HelpHandler* s) : _successor(s){}
virtual void HandleHelp();
private:
HelpHandler* _successor;
};
void HelpHandler::HandleHelp(){
if(_successor)
{
_successor->HandleHelp();
}
}
*Representing requests.
void Handler::HandlerRequest(Request* theRequest)
{
switch(theRequest->GetKind())
{
case Help:
HandleHelp((HelpRequest*)theRequest);
break;
case Print:
HandlePrint((PrintRequest*)theRequest);
break;
//...
default:
//...
break;
}
}
class ExtendedHandler:public Handler{
public:
virtual void HandleRequest(Request* theRequest);
//...
};
void ExtendedHandler::HandleRequest(Request* theRequest)
{
switch(theRequest->GetKind())
{
case Preview:
HandlePre((PreRequest*)theRequest);
break;
default:
Handler::HandleRequest(theRequest);
break;
}
}
Sample Code://C++,This is not a program
The following example illustrates how a chain of responsibility can handle requests for an on-line help system.
typedef int Topic;
const Topic NO_HELP_TOPIC=-1;
class HelpHandler{
public:
HelpHandler(HelpHandler* =0,Topic = NO_HELP_TOPIC);
virtual bool HasHelp();
virtual void SetHandler(HelpHandler*,Topic);
virtual void HandleHelp();
private:
HelpHandler* _successor;
Topic _topic;
};
HelpHandler::HelpHandler(HelpHandler* h,Topic t): _successor(h),_topic(t){}
bool HelpHandler::HasHelp(){return _topic!=NO_HELP_TOPIC;}
void HelpHandler::HandleHelp(){
if(_successor!=0)
_successor->HandleHelp();
}
class Widget:public HelpHandler{
protected:
Widget(Widget* parent,Topic t=NO_HELP_TOPIC);
private:
Widget* _parent;
};
Widget::Widget(Widget* w,Topic t):HelpHandler(w,t){
_parent=w;
}
class Button:public Widget{
public:
Button(Widget* d,Topic t=NO_HELP_TOPIC);
virtual void HandleHelp();
//Widget operations that Button overrides...
};
Button::Button(Widget* h,Topic t):Widget(h,t){}
void Button::HandleHelp(){
if(HasHelp())
{
//offer help on the button
}
else{
HelpHandler::HandleHelp();
}
}
class Dialog:public Widget{
public:
Dialog(HelpHandler* h,Topic t=NO_HELP_TOPIC);
virtual void HandleHelp();
//Widget operations that Dialog overrides...
};
Dialog::Dialog(HelpHandler* h,Topic t):Widget(0){
SetHandler(h,t);
}
void Dialog::HandleHelp(){
if(HasHelp())
{
//offer help on the dialog
}
else{
HelpHandler::HandleHelp();
}
}
class Application:public HelpHandler{
public:
Application(Topic t):HelpHandler(0,t){}
virtual void HandleHelp();
//application-specific operations
};
void Application::HandleHelp(){
//show a list of help topics
}
//How to use? The handle will be passed to application finally.you can //change the topic to catch the handle in the mid of chain.
Application* application=new Application(3);
Dialog* dialog=new Dialog(application,-1);
Dialog* button=new Button(dialog,-1);
button->HandleHelp();
Related patterns:
Chain of responsibilities if often applied in conjunction with Composite.There,a component’s parent can act as its successor.
II.Command
Intent:
Encapsulate a request as an object,thereby letting you parameterize clients with different requests,queue or log requests,and support undoable operations.
Applicability:
Use the Command pattern when you want to:
*parameterize objects by an action to perform.
*specify,queue,and excute requests at different times.
*support undo.
*support logging changes so that they can be reapplied in case of a system crash.
*structure a system around high-level operations built on primitives operations.
Structure:
Collaborations:
The following diagram shows the interactions between these objects.It illustrates how command decouples the invoker from the receiver(and the request it carries out.)
Consequences:
The command pattern has the following consequences:
*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 like any other object.
*You can assemble commands into a composite command.
*It’s easy to add new Commands,because you don’t have to changing existing classes.
Implementation:
*How intelligent should a command be?
*Supporting undo and redo.
A ConcreteCommand class might need to store additional state to do so.This state can include:
The receiver object,which actually carries out operations in response to the request,
the arguments to the operation performed on the receiver,and
any original values in the receiver that can change as a result of handling the request.The receiver must provide operations that let the command return the receiver to its prior state.
*Avoiding error accumulation in the undo process.
*Using C++ templates.
Sample Code://C++,This is not a program
```cpp
class Command
{
virtual ~Command();
virtual void Execute()=0;
protected:
Command();
};
class OpenCommand:public Command{
public:
OpenCommand(Application*);
virtual void Execute();
protected:
virtual const char* AskUser();
private:
Application* _application;
char* _response;
};
OpenCommand::OpenCommand(Application* a){
_application=a;
}
void OpenCommand::Execute(){
const char* nteame=AskUser();
if(name!=0)
{
Document* document=new Document(name);
_application->Add(document);
document->Open();
}
}
class PasteCommand:public Command{
public:
PasteCommand(Document*);
virtual void Execute();
private:
Document* _document;
};
PasteCommand::PasteCommand(Document* doc){
_document=doc;
}
void PasteCommand::Execute(){
_document->Paste();
}
/*For simple commands that aren't undoable and don't require arguments,
we can use a class template to parameterize the command's receiver*/
template<class Receiver>
class SimpleCommand:public Command{
public:
typedef void (Receiver::* Action)();
SimpleCommand(Receiver* r,Action a):
_receiver(r),_action(a){}
virtual void Execute();
private:
Action _action;
Receiver* _receiver;
};
template<class Receiver>
void SimpleCommand<Receiver>::Execute(){
(_receiver->*_action)();
}
//How to use?
MyClass * receiver=new MyClass;
//...
Command* aCommand=new SimpleCommand<MyClass>(receiver,&MyClass::Action);
//...
aCommand->Execute();
//The flowing shows a more complicated situation.
class MacroCommand:public Command{
public:
MacroCommand();
virtual ~MacroCommand();
virtual void Add(Command*);
virtual void Remove(Command*);
virtual void Execute();
private:
List<Command*>* _cmds;
};
void MacroCommand::Execute(){
ListIterator<Command*> i(_cmds);
for(i.First();!i.IsDone();i.Next())
{
Command* c=i.CurrentItem();
c->Execute();
}
}
void MacroCommand::Add(Command* c)
{
_cmds->Append(c);
}
void MacroCommand::Remove(Command*c)
{
_cmds->Remove(c);
}
Related Patterns:
A Composite can be used to implement MacroCommands.
A Memento can keep state the command requires to undo its effect.
A command that must be copied before being placed on the history list acts as a Prototype.
III.Interpreter
Intent:
Given a language,define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
The Interpreter pattern uses a class to represent each grammar rule.
For example:
The abstract syntax tree:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200629160631704.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZqeV9oaGho,size_16,color_FFFFFF,t_70)represents the regular expression:
raining&(dogs|cats)*
Applicability:
Use the interpreter pattern when there is a language to interpret,and you can represent statements in the language as abstract syntax trees.The interpreter pattern works best when:
*The grammar is simple.
*Efficiency is not a critical pattern.
Structure:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200629161138975.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZqeV9oaGho,size_16,color_FFFFFF,t_70)
Consequences:
The interpreter pattern has the following benefits and liabilities:
*It's easy to change and extend the grammar.
*Implementing the grammar is easy,too.
*Complex grammar are hard to maintain.
*Adding new ways to interpret expressions.
Implementation:
*Creating the abstract syntax tree.
*Defining the Interpret operation.
*Sharing terminal symbols with the Flyweight pattern.
Sample Code://C++,Not a program
The example is a system for manipulating and evaluating Boolen expression implemented in C++.The terminal symbols in this language are Boolen variables,that is,the constants true and false.Nonterminal symbols represent expressions containing the operators and ,or ,not.The gammar is defined follows:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200629163903742.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ZqeV9oaGho,size_16,color_FFFFFF,t_70)
```cpp
class BooleanExp{
public:
BooleanExp();
virtual ~BooleanExp();
virtual bool Evaluate(Context&)=0;
virtual BooleanExp* Replace(const char*,BooleanExp&)=0;
virtual BooleanExp* Copy() const=0;
};
class Context{
public:
bool Lookup(const char*);
void Assign(VariableExp*,bool);
};
class VariableExp:public BooleanExp{
public:
VariableExp(const char*);
virtual ~VariableExp();
virtual bool Evaluate(Context&);
virtual BooleanExp* Replace(const char*,BooleanExp&);
virtual BooleanExp* Copy() const;
private:
char* _name;
};
VariableExp::VariableExp(const char* name)
{
strcpy(_name,name);
}
bool VariableExp::Evaluate(Context& aContext){
return aContext.Lookup(_name);
}
BooleanExp* VariableExp::Copy()const{
return new VariableExp(_name);
}
BooleanExp* VariableExp::Replace(const char* name,BooleanExp& exp)
{
if(strcmp(name,_name)==0)
return exp.Copy();
else
return new VariableExp(_name);
}
class AndExp:public BooleanExp{
public:
AndExp(BooleanExp*,BooleanExp*);
virtual ~AndExp();
virtual bool Evaluate(Context&);
virtual BooleanExp* Replace(const char*,BooleanExp&);
virtual BooleanExp* Copy()const;
private:
BooleanExp* _operand1;
BooleanExp* _operand2;
};
AndExp::AndExp(BooleanExp* op1,BooleanExp* op2)
{
_operand1=op1;
_operand2=op2;
}
bool AndExp::Evaluate(Context& aContext)
{
return
_operand1->Evaluate(aContext)&&
_operand2->Evaluate(aContext);
}
BooleanExp* AndExp::Copy()const{
return new AndExp(_operand1->Copy(),_operand2->Copy());
}
BooleanExp* AndExp::Replace(const char* name,BooleanExp& exp)
{
return new AndExp(_operand1->Replace(name,exp),_operand2->Replace(name,exp));
}
Related pattern:
Composite:The abstract syntax tree is an instance of the Composite pattern.
Flyweight:show how to share terminal symbols within the abstract syntax tree.
Iterator:The interpreter can use an Iterator to traverse the structure
Vistor:can be used to maintain the behavior in each node in the astract syntax tree in one class.
IV.Iterator
Intent:
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Applicability:
Use the Iterator pattern:
*To access an aggregate object’s contents without exposing its internal representation.
*To support multiple traversals of aggregate objects.
*To provide a uniform interface for traversing different aggregate structures(that is,to support polymorphic iteration)
Structure:
Consequences:
*It supports variations in the traversal of an aggregate.
*Iterators simplify the Aggregate interface.
*More than one traversal can be pending on an aggregate.
Implementation:
*Who controls the iteration?external iterator or internal iterator.
*Who defines the traversal algorithm?aggregate or iterator
*How robust is the iterator?
*Additional Iterator operations.
*Using polymorphic iterators in C++.
*Iterators may have privileged access.
*Iterators for composites.
*Null iterators.A NullIterator is a degenerate iterator that’s helpful for handling boundary conditions.
Sample code://C++,This is not a program.
class AbstractList{
public:
virtual Iterator<Item>* CreateIterator() const=0;
//...
};
template<class Item>
class List:public AbstractList<Item>{
public:
List(long size=DEFAULT_LIST_CAPACITY);
long Count()const;
Item& Get(long index)const;
//...
};
template<class Item>
Iterator<Item>* List<Item>::CreateIterator() const{
return new ListIterator<Item>(this);
}
template<class Item>
class Iterator{
public:
virtual void First()=0;
virtual void Next()=0;
virtual bool IsDone() const=0;
virtual Item CurrentItem() const =0;
protected:
Iterator();
};
template<class Item>
class ListIterator:public Iterator<Item>{
public:
ListIterator(const List<Item>* aList)
virtual void First();
virtual void Next();
virtual bool IsDone() const;
virtual Item CurrentItem() const ;
protected:
const List<Item>* _list;
long _current;
};
template<class Item>
ListIterator<Item>::ListIterator(const List<Item>* aList){
_list=aList;
_current=0;
}
template<class Item>
void ListIterator<Item>::First(){
_current=0;
}
template<class Item>
void ListIterator<Item>::Next(){
_current++;
}
template<class Item>
bool ListIterator<Item>::IsDone(){
return _current>=_list->Count();
}
template<class Item>
Item ListIterator<Item>::CurrentItem(){
if(IsDone())
throw IteratorOutOfBounds;
return _list->Get(_current);
}
//Use proxy pattern to delete list for clients
template<class Item>
class IteratorPtr{
public:
IteratorPtr(Iterator<Item>* i):_i(i){}
~Iterator(){delete _i;}
Iterator<Item>* operator->(){return _i;}
Iterator<Item>& operator*(){return *_i;}
private:
//disallow copy and assignment to avoid
//multiple deletions of _i:
IteratorPtr(Const IteratorPtr);
IteratorPtr& operator=(const IteratorPtr&);
private:
Iterator<Item>*_i;
};
//How to use ?
void PrintEmployees(Iterator<Employee*>& i)
{
for(i.First();!i.IsDone();i.Next())
i.CurrentItem()->Print();
}
AbstractList<Employee*>* employees;
IteratorPtr<Employee*>iterator(employees->CreateIterator());
PrintEmployees(*iterator);
//The following example shows what a internal ListIterator look like.
//We use subclassing to perform the special operation.
template<class Item>
class ListTraverser{
public:
ListTraverser(List<Item>* aList);
bool Traverse();
protected:
virtual bool ProcessItem(const Item&)=0;
private:
ListIterator<Item> _iterator;
};
template<class Item>
ListTraverser<Item>::ListTraverser(List<Item>* aList):_iterator(aList){}
template<class Item>
bool ListTraverser<Item>::Traverse(){
bool result=false;
for(_iterator.First();!_iterator.IsDone();_iterator.Next())
{
result=ProcessItem(_iterator.CurrentItem);
if(result= =false)
break;
}
return result;
}
//Internal Iterator to print first 10 employees
class PrintNEmployees:public ListTraverser<Employee*>
{
public:
PrintNEmployees(List<Employee*>* aList,int n)
{
ListTraverser<Employee*>(aList);
_total=n;
_count=0;
}
protected:
bool ProcessItem(Employee* const&);
private:
int _total;
int _count;
};
bool PrintNEmployees::ProcessItem(Employee* const& e)
{
_count++;
e->Print();
return _count<_total;
}
//How to use? for internal Iterator
List<Employee*>* employees;
//...
PrintNEmployees pa(employees,10);
pa.Traverse();
//for external Iterator
ListIterator<Employee*> i(employees);
int count=0;
for(i.First();!i.IsDone();i.Next())
{
count++;
i.CurrentItem()->Print();
if(count>=10)
break;
}
//What's more ,Internal iterators can encapsulate different kinds of iteration.
template<class Item>
class FilteringListTraverser{
public:
FilteringListTraverser(List<Item>* aList);
bool Traverse();
protected:
virtual bool ProcessItem(const Item&)=0;
virtual bool TestItem(const Item&)=0;
private:
ListIterator<Item> _iterator;
}
bool FilteringListTraverser<Item>::Traverse(){
bool result=false;
for(_iterator.First();!_iterator.IsDone();_iterator.Next())
{
if(TestItem(_iterator.CurrentItem())){
result=ProcessItem(_iterator.CurrentItem);
if(result==false)
break;
}
}
return result;
}
Related patterns:
Composite:Iterators are often applied to recursive structures such as Composite
Factory Method:Polymorphic iterators rely on factory methods to instantiate the appropriate Iterator subclass.
Memento is often used in conjucetion with the Iterator pattern.An iterator can use a memento to capture the state of an iteration.The iterator stores the memento internally.
V.Mediator
Intent:
Define an object that encapsulates how a set of objects interact.Mediator promotes loose couping by keeping objects from referring to each other explicitly,and it lets you vary their interaction independently.
Applicability:
Use the Mediator pattern when:
*a set of objects communicate in well-defined but complex ways.The resulting interdependencies are unstructured and difficult to understand.
*reusing an object is difficult because it refers to and communicates with many other objects.
*a behavior that’s distributed between several classes should be customizable without a lot of sublassing.
Structure:
A typical object structure might look like this:
Consequences:
The Mediator pattern has the following benefits and drawbacks:
*It limits subclassing.
*It decouples colleagues.
*It simplifies object protocols.
*It abstracts how objects cooperate.
*It centralizes control(a draw back)
Implementation:
*Omitting the abstract Mediator class.
*Colleague-Mediator communication.
Sample Code:
class DialogDirector{
public:
virtual ~DialogDirector();
virtual void ShowDialog();
virtual void WidgetChanged(Widget*)=0;
protected:
DialogDirector();
virtual void CreateWidgets()=0;
};
class Widget{
public:
Widget(DialogDirector*);
virtual void Changed();
virtual void HandleMouse(MouseEvent& event);
//...
private:
DialogDirector* _director;
};
void Widget::Changed(){
_director->WidgetChanged(this);
}
class ListBox::public Widget{
public:
ListBox(DialogDirector*);
virtual const char* GetSelection();
virtual void SetList(List<char*>* listItems);
virtual void HandleMouse(MouseEvent& event);
//...
};
class EntryField:public Widget{
public:
EntryField(DialogDirector*);
virtual void SetText(const char* text);
virtual const char* GetText();
virtual void HandleMouse(MouseEvent& event);
//...
};
class Button:public Widget{
public:
Button(DialogDirector*);
virtual void SetText(const char* text);
virtual void HandleMouse(MouseEvent& event);
//...
};
void Button::HandleMouse(MouseEvent& event)
{
//...
Changed();
}
class FontDialogDirector:public DialogDirector{
public:
FontDialogDirector();
virtual ~FontDialogDirector();
virtual void WidgetChanged(Widget*);
protected:
virtual void CreateWidgets();
private:
Button* _ok;
Button* _cancel;
ListBox* _fontList;
EntryField* _fontName;
};
void FontDialogDirector::CreateWidgets(){
_ok=new Button(this);
_cancel=new Button(this);
_fontList=new ListBox(this);
_fontName=new EntryField(this);
//fill the listBox with the available font names.
//assemble the widgets in the dialog
}
void FontDialogDirector::WidgetChanged(Widget* theChangedWidget)
{
if(theChangedWidget==_fontList)
{
_fontName->SetText(_fontList->GetSelection());
}
else if(theChangedWidget==_ok)
{
//apply font change and dismiss dialog
//...
}
else if(theChangedWidget==_cancel)
{
//dismiss dialog
}
}
Related pattern:
Facade differs from Mediator in that it abstracts a subsystem of objects to provide a more convenient interface.Its protocol is unidirectional;that is,Facade objects make requests of the subsystem classes but not vice versa.In contrast,Mediator enables cooperative behavior that colleague objects don’t or can’t provide,and the protocol is multidirectional.
Colleagues can communicate with the mediator using the Observer pattern.
VI. Memento
Intent:
Without violating encapsulation,capture and externalize an object’s internal state so that the object can be restored to this state later.
A memento is an object that stores a snapshot of the internal state of another object—The memento’s originator.
Applicability:
Use the Memento pattern when:
*a snapshot of an object’s state must be saved so that it can be restored to that state later and
*a direct interface to obtaining the state would expose implementation details and break the object’s encapsulation.
Structure:
Collaborations:
*A caretaker requests a memento from an originator,holds it for a time,and passes it back to the originator,as the following interaction diagram illustrates:
Sometimes the caretaker won’t pass the memento back to the originator,because the originator might never need to revert to an earlier state.
*Mementos are passive.Only the originator that created a memento will assign or retrieve its state.
Consequences:
*Preserving encapsulation boundaries.
*It simplifies originator.
*Using mementos might be expensive.
*Defining narrow and wide interfaces.
*Hidden costs in caring for mementos.
Implementation:
*Language support.Mementos have two interfaces:a wide one for originators and a narrow one for other objects.
eg://C++
class State;
class Originator{
public:
Memento* CreateMemento();
void SetMemento(const Memento*);
//...
private:
State* _state;
//...
};
class Memento{
public:
//narrow public interface
virtual ~Memento();
private:
//private members accessible only to originator
friend class Originator;
Memento();
void SetState(State*);
State* GetState();
//...
private:
State* _state;
};
*Storing incremental changes.
Sample Code://C++,Not a program.
class Graphic;
class MoveCommand{
public:
MoveCommand(Graphic* target,const Point& delta);
void Execute();
void Unexecute();
private:
ConstraintSolverMemento* _state;
Point _delta;
Graphic* _target;
};
class ConstraintSolver{
public:
static ConstraintSolver* Instance();
void Solve();
void AddConstraint(Graphic* startConnection,Graphic* endConnection);
void RemoveConstraint(Graphic* startConnection,Graphic* endConnection);
ConstraintSolverMemento* CreateMemento();
void SetMemento(ConstraintSolverMemento*);
private:
//...
};
class ConstraintSolverMemento{
public:
virtual ~ConstraintSolverMemento();
private:
friend class ConstraintSolver;
ConstraintSolverMemento();
//private Constraint Solver State
};
/*We can implement MoveCommand like this*/
void MoveCommand::Execute(){
ConstraintSolver* solver=ConstraintSolver::Instance();
_state=solver->CreateMemento();
_target->Move(_delta);
solver->Solve();
}
void MoveCommand::Unexecute(){
ConstraintSolver* solver=ConstraintSolver::Instance();
_target->Move(-_delta);
solver->SetMemento(_state);
solver->Solve();
}
Related patterns:
*Command:Commands can use mementos to maintain state for undoable operations.
*Iterator:Mementos can be use for iteration .
VII.Observer
Intent:
Define a one-to-many dependency between objects so that hen one object changes state,all its dependents are notified and updated automatically.
It is also known as Publish-Subscribe.
Applicability:
Use the Observer pattern in any of the following situations:
*When an abstraction has two aspects ,one dependent on the other.Encapsulating these aspects in separate objects lets you vary and reuse them independently.
*When a change to one object requires changing others,and you don’t know how many objects need to be changed.
*When an object should be able to notify other objects without making asumptions about who these objects are.In other words,you don’t want these objects tightly coupled.
Structure:
Collaborations:
*ConcreteSubject notifies its observers whenever a change occurs that could make its observers’ state inconsistent with its own.
*After being informed of a change in the concrete subject,a ConcreteObserver object may query the subject for information.ConcreteObserver uses this information to reconcile its state with that of the subject.
Consequences:
*Abstract coupling between Subject and Observer.All a subject knows is that it has a list of observers,each confroming to the simple interface of the abstract Observer class.The subject doesn’t know the concrete class of any observer.
*Support for broadcast communication.
*Unexpected updates.
Implementation:
*Mapping subjects to their observers.
*Observing more than one subject.
*Who triggers the update?
Here are two options:
(a)Have state-setting operations on Subject call Notify after they change the subject’s state.
(b)Make clients responsible for calling Notify at the right time.
*Dangling references to deleted subjects.
*Making sure Subject state is self-consistent before notification.
*Avoiding observer-specific update protocols:the push and pull models.
*specifying modifications of interest explicitly.
*Encapsulating complex update semantics.
*Combining the Subject and Observer classes.
Sample Code://C++,Not a program
class Observer{
public:
virtual ~Observer();
virtual void Update(Subject* theChangedSubject)=0; //support multiple subjects
protected:
Observer();
};
class Subject{
public:
virtual ~Subject();
virtual void Attach(Observer*);
virtual void Detach(Observer*);
virtual void Notify();
protected:
Subject();
private:
List<Observer*> *_observers;
};
void Subject::Attach(Observer* o)
{
_observers->Append(o);
}
void Subject::Detach(Observer* o)
{
_observers->Remove(o);
}
void Subject::Notify(){
ListIterator<Observer*> i(_observers);
for(i.First();!i.IsDone();i.Next())
i.CurrentItem()->Update(this);
}
class ClockTimer:public Subject{
public:
ClockTimer();
virtual int GetHour();
virtual int GetMinute();
virtual int GetSecond();
void Tick();
};
void ClockTimer::Tick(){
//Update internal time-keeping state
//...
Notify();
}
class DigitalClock:public Widget,public Observer{
public:
DigitalClock(ClockTimer*);
virtual ~DigitalClock();
virtual void Update(Subject*);
//overrides Observer operation
virtual void Draw();
//overrides Widget operation;
//defines how to draw the digital clock
private:
ClockTimer* _subject;
};
DigitalClock::DigitalClock(ClockTimer* s)
{
_subject=s;
_subject->Attach(this);
}
DigitalClock::~DigitalClock(){
_subject->Detach(this);
}
/*Before the Update operation draws the clock face,
it checks to make sure the notifying subject is clock's subject*/
void DigitalClock::Update(Subject *theChangedSubject)
{
if(theChangedSubject==_subject)
Draw();
}
void DigitalClock::Draw(){
int hour=_subject->GetHour();
int minute=_subject->GetMinute();
///etc
}
class AnalogClock:public Widget,public Observer{
public:
AnalogClock(ClockTimer*);
virtual void Update(Subject*);
virtual void Draw();
//...
};
//How to use?
ClockTimer* timer=new ClockTimer;
AnalogClock* analogClock=new AnalogClock(timer);
DigitalClock* digitalClock=new DigitalClock(timer);
Related Patterns:
Mediator:By encapsulating complex update semantics,the ChangeManager acts as mediator between subjects and observers.
Singleton:The ChangeManager may use the Singleton pattern to make it unique and globally accessible.
VIII. State
Intent:
Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.
Applicability:Use the State pattern in either of the following cases:
*An object’s behavior depends on its state,and it must change its behavior at run-time depending on that state.
*Operations have large,multipart conditional statements that depend on the object’s state.
Structure:
Consequences:
*It localizes state-specific behavior and partitions behavior for different states.The State pattern puts all behavior associated with a particular state into one object.
*It makes state transitions explicit.
*State objects can be shared.
Implementation:
*Who defines the state transitions?
*A table-based alternative.
*Creating and destroying State objects.
*Using dynamic inheritance.
Sample Code://C++,Not a program
class TCPOctetStream;
class TCPConnection{
public:
TCPConnection();
void ActiveOpen();
void PassiveOpen();
void Close();
void Send();
void Acknowledge();
void Synchronize();
void ProcessOctet(TCPOctetStream*);
private:
friend class TCPState;
void ChangeState(TCPState*);
TCPState* _state;
};
class TCPState{
public:
virtual void Transmit(TCPConnection*,TCPOctetStream*);
virtual void ActiveOpen(TCPConnection*);
virtual void PassiveOpen(TCPConnection*);
virtual void Close(TCPConnection*);
virtual void Synchronize(TCPConnection*);
virtual void Acknowledge(TCPConnection*);
virtual void Send(TCPConnection*);
protected:
void ChangeState(TCPConnection*,TCPState*);
};
TCPConnection::TCPConnection(){
//_state=TCPClosed::Instance();
}
void TCPConnection::ChangeState(TCPState*s)
{
_state=s;
}
void TCPConnection::ActiveOpen(){
_state->ActiveOpen(this);
}
void TCPConnection::PassiveOpen(){
_state->PassiveOpen(this);
}
void TCPConnection::Close(){
_state->Close(this);
}
void TCPConnection::Acknowledge(){
_state->Acknowledge(this);
}
void TCPConnection::Synchronize(){
_state->Synchronize(this)
}
void TCPState::Transmit(TCPConnection*,TCPOctetStream*){}
void TCPState::ActiveOpen(TCPConnection*){}
void TCPState::PassiveOpen(TCPConnection*){}
void TCPState::Close(TCPConnection*){}
void TCPState::Synchronize(TCPConnection*){}
void TCPState::ChangeState(TCPConnection* t,TCPState*s)
{
t->ChangeState(s);
}
class TCPEstablished:public TCPState{
public:
static TCPState* Instance();
virtual void Transmit(TCPConnection*,TCPOctetStream*);
virtual void Close(TCPConnection*);
};
class TCPListen:public TCPState{
public:
static TCPState* Instance();
virtual void Send(TCPConnection*);
//...
};
class TCPClosed:public TCPState{
public:
static TCPState* Instance();
virtual void ActiveOpen(TCPConnection*);
virtual void PassiveOpen(TCPConnection*);
//...
};
void TCPClosed::ActiveOpen(TCPConnection* t)
{
//send SYN,reveive SYN,ACK,etc
ChangeState(t,TCPEstablished::Instance());
}
void TCPClosed::PassiveOpen(TCPConnection*t)
{
ChangeState(t,TCPListen::Instance());
}
void TCPEstablished::Close(TCPConnection*t)
{
//send FIN,receive ACK of FIN
ChangeState(t,TCPListen::Instance())
}
void TCPEstablished::Transmit(TCPConnection*t,TCPOctetStream*o)
{
t->ProcessOctet(o);
}
void TCPListen::Send(TCPConnection*t)
{
//send SYN,receive SYN,ACK,etc.
ChangeState(t,TCPEstablished::Instance());
}
/*
After performing state-specific work,these operations call
ChangeState operation to change the state of the TCPConnection.
*/
Related patterns:
The flyweight pattern explains when and how State objects can be shared.State objects are often Singletons.
IX.Strategy
Intent:
Define a family of algorithms,encapsulate each one,and make them interchangeable.Strategy lets the algorithms vary independently from clients that use it.
Applicability:Use the Strategy pattern when:
*many related classes differ only in their behavior.Strategies provide a way to configure a class with one of many behaviors.
*you need different variants of an algorithm.
*an algorithm uses data that clients shouldn’t know about.
*a class defines many behaviors,and these appear as multiple conditional statements in its operation.
Structure:
Consequences:
Benefits:
*Families of related algorithms.
*An alternative to subclassing.
*Strategies eliminate conditional statements.
*A choice of implementations.
Drawbacks:
*Clients must be aware of different Strategies.
*Communication overhead between strategy and context.
*Increased number of objects.
Implementation:
*Defining the Strategy and Context interfaces.The Strategy and Context interfaces must give a ConcreteStrategy efficient access to any data it need from a context,and vice versa.
*Strategies as template parameters.This technique is only applicable if (1)the Strategy can be selected at compile-time,and (2)it does not have to be changed at run-time.
template<class AStrategy>
class Context
{
void Operation(){theStrategy.DoAlgorithm();}
//...
private:
AStrategy theStrategy;
};
class MyStrategy{
public:
void DoAlgorithm();
};
Context<MyStrategy>aContext;
*Making Strategy objects optimal.
Sample Code://C++,Not a program
class Composition{
public:
Composition(Compositor*);
void Repair();
private:
Compositor* _compositor;
Component* _components;
int _componentCount;
int _lineWidth;
int *_lineBreaks;/*The position of linebreaks in components*/
int _lineCount;
};
class Compositor{
public:
virtual int Compose(Coord natural[],Coord stretch[],Coord shrink[],
int componentCount,int lineWidth ,int breaks[])=0;
protected:
Compositor();
};
void Composition::Repair(){
Coord* natural;
Coord* stretchability;
Coord* shrinkability;
int componentCount;
int *break;
//prepare the arrays with the desired component sizes
//...
//determine where the breaks are:
int breakCount;
breakCount=_compositor->Compose(natural,stretchability,shrinkability,componentCount,_lineWidth,breaks);
//lay out components according to breaks
//...
}
class SimpleCompositor:public Compositor{
public:
SimpleCompositor();
virtual int Compose(Coord natural[],Coord Stretch[],Coord shrink[],
int componentCount,int lineWidth,int breaks[]);
//...
};
class TeXCompositor:public Compositor{
public:
TeXCompositor();
virtual int Compose(Coord natural[],Coord Stretch[],Coord shrink[],
int componentCount,int lineWidth,int breaks[]);
//...
};
class ArrayCompositor:public Compositor{
public:
ArrayCompositor(int interval);
virtual int Compose(Coord natural[],Coord Stretch[],Coord shrink[],
int componentCount,int lineWidth,int breaks[]);
//...
};
//How to use?
Composition* quick=new Composition(new SimpleCompositor);
Composition* slick=new Composition(new TeXCompositor);
Composition* iconic=new Composition(new ArrayCompositor(100));
Related patterns:
Flyweight:Strategy objects often make good flyweights.
X.Template Method
Intent:
Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
Applicability:The Template Method pattern should be used
*to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary.
*when common behavior among subclasses should be factored and localized in a common class to avoid code duplication.
- to control subclasses extensions.
Structure:
Consequences:
Template methods are a fundamental technique for code reuse.
Tempalte methods lead to an inverted control structure that’s sometimes referred to as “the Holldwood principle”,that is,“Don’t call us,we’ll call you”.
Template methods call the following kinds of operations:
*concrete operations(either on the ConcreteClass or on client classes);
*concrete AbstractClass operations;
*primitive operations;
*factory methods;
*hook operations.
Implementation:
Three implementation issues are worth noting:
*Using C++ access control.
*Minimizing primitive operations.
*Naming conventions.
Sample Code://C++,Not a program
void View::Display(){
SetFocus();
DoDisplay();
ResetFocus();
}
void View::DoDisplay(){}
void MyView::DoDisplay(){
//render the view's contents
}
Related Patterns:
Factory Methods are often called by template methods.
Strategy:Template methods use inheritance to vary part of an algorithm.Strategies use delegation to vary the entire algorithm.
XI.Visitor
Intent:
Represent an operation to be performed on the elements of an object structure.Visitor lets you define a new operation without changing the classes of the elements on which it operates.
With the Visitor pattern,you define two class hierarchies:one for the elements being operated on and one for the visitors that define operations on the elements.You create a new operation by adding a new subclass to the visitor class hierarchy.
Applicability:Use the visitor pattern when
*an object structure contains many classes of objects with differing interfaces,and you want to perform operations on these objects that depend on their concrete classes.
*many distinct and unrelated operations need to be performed on objects in an object structure,and you want to avoid "polluting"their classes with these operations.
*the classes defining the object structure rarely change,but you often want to define new operations over the structure.
Structure:
Collaborations:
*A client that uses the Visitor pattern must create a ConcreteVisitor object and then traverse the object structure,visiting each element with the visitor.
*When an element is visited,it calls the Visitor operation that corresponds to its class.
The following interaction diagram illustrates the collaborations between an object structure ,a visitor,and two elements:
Consequences:
Benefits:
*Visitor makes adding new operations easy.
*A visitor gathers related operations and separates unrelated ones.
*Visiting across class hierarchies.
*Accumulating state.
Liabilities:
*Adding new ConcreteElement classes is hard.
*Breaking encapsulation.
Implementation:
Each object structure will have an associated Visitor class.
The Visitor class would be declared like this in C++:
class Visitor{
public:
virtual void VisitElementA(ElementA *);
virtual void VisitElementB(ElementB *);
virtual void VisitCompositeElement(CompositeElement*);
//and so on for other concrete elements
protected:
Visitor();
};
class Element{
public:
virtual ~Element();
virtual void Accept(Visitor&)=0;
protected:
Element();
};
class ElementA:public Element{
public:
ElementA();
virtual void Accept(Visitor& v){v.VisitElementA(this);}
};
class ElementB:public Element{
public:
ElementB();
virtual void Accept(Visitor& v){v.VisitElementB(this);}
};
class CompositeElement:public Element{
public:
virtual void Accept(Visitor&);
private:
List<Element*>* _children;
};
void CompositeElement::Accept(Visitor& v)
{
ListIterator<Element*> i(_children);
for(i.First();!i.IsDone();i.Next())
{
i.CurrentItem()->Accept(v);
}
v.VisitCompositeElement(this);
}
Here are two other implementation issues that arise when you apply the Visitor pattern:
*Double dispatch.This is the key to the Visitor pattern:The operation that gets executed depends on both the type of Visitor and the type of Element it visits.
*Who is responsible for traversing the object structure?We can put responsibility for traversal in any of three places:in the object structure(usually),in the visitor,or in a separate iterator object.
Sample Code://C++,Not a program
class Equipment{
public:
virtual ~Equipment();
const char* Name(){return _name;}
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
virtual void Accept(EquipmentVisitor&);
protected:
Equipment(const char*);
private:
const char* _name;
};
class EquipmentVisitor{
public:
virtual ~EquipmentVisitor();
virtual void VisitFloppyDisk(FloppyDisk*);
virtual void VisitCard(Card*);
virtual void VisitChassis(Chassis*);
virtual void VisitBus(Bus*);
//and so on for other concrete subclasses of Equipment
protected:
EquipmentVisitor();
};
void FloppyDisk::Accept(EquipmentVisitor& visitor)
{
visitor.VisitFloppyDisk(this);
}
void Chassis::Accept(EquipmentVisitor& visitor)
{
for(ListIterator<Equipment*> i(_parts);!i.IsDone();i.Next())
{
i.CurrentItem()->Accept(visitor);
}
visitor.VisitChassis(this);
}
class PricingVisitor:public EquipmentVisitor{
public:
PricingVisitor();
Currency& GetTotalPrice();
virtual void VisitFloppyDisk(FloppyDisk*);
virtual void VisitCard(Card*);
virtual void VisitChassis(Chassis*);
virtual void VisitBus(Bus*);
//...
private:
Currency _total;
};
void PricingVisitor::VisitFloppyDisk(FloppyDisk* e)
{
_total+=e->NetPrice();
}
void PricingVisitor::VisitChassis(Chassis* e)
{
_total+=e->DiscountPrice();
}
class InventoryVisitor:public Equipment{
public:
InventoryVisitor();
Inventory& GetInventory();
virtual void VisitFloppyDisk(FloppyDisk*);
virtual void VisitCard(Card*);
virtual void VisitChassis(Chassis*);
virtual void VisitBus(Bus*);
//...
private:
Inventory _inventory;
};
void InventoryVisitor::VisitFloppyDisk(FloppyDisk* e)
{
_inventory.Accumulate(e);
}
void InventoryVisitor::VisitChassis(Chassis *e)
{
_inventory.Accumulate(e);
}
//How to use?
Equipment* component;
InventoryVisitor visitor;
component->Accept(visitor);
Related patterns:
Composite:Visitors can be used to apply an operation over an object structure defined by the Composite pattern.
Interpreter:Visitor may be applied to do the interpretation.