BEHAVIOURAL PATTERNS (OOAD)
a) Avoid coupling the sender of a request to its receiver by more than one object a chance to handle a request.
b) Chain the receiving objects and pass the request along the chain until an object handles it.
Example:
class abs_handler
{
protected:
abs_handler* handle;
public:
void setSuccessor(abs_handler* handle)
{
this->handle = handle;
}
virtual void handleRequest(int request) = 0;
};
class concreteHandler1 : public abs_handler
{
public:
void handleRequest(int request)
{
if ((request >= 0) && (request < 10))
{
cout << "Handled : concreteHandler1" << endl;
}
else if(handle != nullptr)
{
handle->handleRequest(request);
}
}
};
class concreteHandler2 : public abs_handler
{
public:
void handleRequest(int request)
{
if ((request >= 10) && (request < 20))
{
cout << "Handled : concreteHandler2" << endl;
}
else if (handle != nullptr)
{
handle->handleRequest(request);
}
}
};
class concreteHandler3 : public abs_handler
{
public:
void handleRequest(int request)
{
if ((request >= 20) && (request < 30))
{
cout << "Handled : concreteHandler3" << endl;
}
else if (handle != nullptr)
{
handle->handleRequest(request);
}
}
};
void ABS_Handler_Function()
{
abs_handler* main_handle1;
abs_handler* main_handle2;
abs_handler* main_handle3;
main_handle1 = new concreteHandler1;
main_handle2 = new concreteHandler2;
main_handle3 = new concreteHandler3;
main_handle1->setSuccessor(main_handle2);
main_handle2->setSuccessor(main_handle3);
int requests[8] = {2, 5, 14, 22, 18, 3, 27, 20};
for (int i = 0; i < 8; i++)
{
main_handle1->handleRequest(requests[i]);
cout << requests[i] << endl;
}
}
Encapsulate a request on an object, thereby letting one parameterise clients with different requests, queue or log requests, and support undoable operations.
Example:
class Receiver
{
public:
void Action()
{
cout << "Receiver::Action" << endl;
}
};
class Command
{
protected:
Receiver* receive;
public:
Command(Receiver* R)
{
this->receive = R;
}
virtual void Execute() = 0;
};
class ConcreteCommand : public Command
{
public:
ConcreteCommand(Receiver* R) : Command(R)
{ }
void Execute()
{
receive->Action();
}
};
class Invoker
{
Command* com;
public:
void ExecuteCommand(Command* com1)
{
this->com = com1;
this->com->Execute();
}
};
void Command_Invoke_Function()
{
Receiver* recObj = new Receiver();
Command* comObj = new ConcreteCommand(recObj);
Invoker* invObj = new Invoker();
invObj->ExecuteCommand(comObj);
}
3) Interpreter:
Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
Example:
class context
{
public:
void DisplayContext()
{
cout << "context::DisplayContext" << endl;
}
};
class abstractExpression
{
public:
virtual void interpret(context ct) = 0;
};
class TerminalExpression : public abstractExpression
{
public:
void interpret(context ct)
{
cout << "TerminalExpression::interpret" << endl;
ct.DisplayContext();
}
};
class NonTerminalExpression : public abstractExpression
{
public:
void interpret(context ct)
{
cout << "NonTerminalExpression::interpret" << endl;
ct.DisplayContext();
}
};
void abstractExpressionFunc()
{
context ct;
vector<abstractExpression*> vec_absExp;
vec_absExp.push_back(new TerminalExpression);
vec_absExp.push_back(new NonTerminalExpression);
vec_absExp.push_back(new TerminalExpression);
vec_absExp.push_back(new NonTerminalExpression);
vector<abstractExpression*>::iterator it;
for (it = vec_absExp.begin(); it != vec_absExp.end(); it++)
{
(*it)->interpret(ct);
cout << endl;
}
}
4) Iterator:
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Example:
template<class T>
class Iterator
{
public:
virtual T First() = 0;
virtual T Next() = 0;
virtual bool IsDone() = 0;
virtual T CurrentItem() = 0;
};
template<class T>
class Aggregate
{
public:
typename vector<T> vect_T;
virtual Iterator<T>* CreateIterator() = 0;
virtual void Add(T addNum) = 0;
};
template<class T>
class ConcreteIterator : public Iterator<T>
{
typename Aggregate<T>* conAggre;
typename vector<T>::iterator it;
int Current;
public:
ConcreteIterator(typename Aggregate<T>* conAggre)
{
this->conAggre = conAggre;
Current = 0;
}
T First()
{
it = conAggre->vect_T.begin();
T first = *it;
return first;
}
T Next()
{
it++;
Current++;
return *it;
}
bool IsDone()
{
return Current >= (conAggre->vect_T.size()) ? true : false;
}
T CurrentItem()
{
T curItem = (conAggre->vect_T).at(Current);
return curItem;
}
};
template<class T>
class ConcreteAggregate : public Aggregate<T>
{
public:
ConcreteAggregate(){}
Iterator<T>* CreateIterator()
{
return (new ConcreteIterator<T>(this));
}
void Add(T addT)
{
Aggregate<T>::vect_T.push_back(addT);
}
};
void Aggregate_Iterator()
{
ConcreteAggregate<int>* conAggre = new ConcreteAggregate<int>;
conAggre->Add(10);
conAggre->Add(20);
conAggre->Add(30);
conAggre->Add(40);
Iterator<int>* conIter = conAggre->CreateIterator();
int i = conIter->First();
while (!conIter->IsDone())
{
cout << conIter->CurrentItem() << endl;
i = conIter->Next();
}
ConcreteAggregate<string>* conAggreString = new ConcreteAggregate<string>;
conAggreString->Add("Apple");
conAggreString->Add("Orange");
conAggreString->Add("Grapes");
conAggreString->Add("Banana");
Iterator<string>* conIterString = conAggreString->CreateIterator();
string str = conIterString->First();
while (!conIterString->IsDone())
{
cout << conIterString->CurrentItem() << endl;
str = conIterString->Next();
}
}
5) Mediator:
a) Define an object that encapsulates how a set of objects interact.
b) Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets one vary their interaction independently.
Example:
class Colleague;
class Mediator
{
public:
virtual void Send(string message, Colleague* colleague) = 0;
};
class Colleague
{
protected:
Mediator* mediator;
public:
Colleague(Mediator* media)
{
mediator = media;
}
};
class ConcreteColleague1 : public Colleague
{
public:
ConcreteColleague1(Mediator* media) : Colleague(media) {}
void Send(string message)
{
mediator->Send(message, this);
}
void Notify(string message)
{
cout << "message: " << message.c_str() << endl;
}
};
class ConcreteColleague2 : public Colleague
{
public:
ConcreteColleague2(Mediator* media) : Colleague(media) {}
void Send(string message)
{
mediator->Send(message, this);
}
void Notify(string message)
{
cout << "message: " << message.c_str() << endl;
}
};
class ConcreteMediator : public Mediator
{
public:
ConcreteColleague1* colleague1;
ConcreteColleague2* colleague2;
void Send(string message, Colleague* colleague)
{
if (colleague == colleague1)
colleague1->Notify(message);
else
colleague2->Notify(message);
}
};
void ConcreteMediator_Function()
{
ConcreteMediator m;
ConcreteColleague1 c_colleague1(&m);
ConcreteColleague2 c_colleague2(&m);
m.colleague1 = &c_colleague1;
m.colleague2 = &c_colleague2;
c_colleague1.Send("How are you");
c_colleague2.Send("Fine. Thanks");
}
6) Memento:
Without violating encapsulation, capture and externalise an object's internal state so that the object can be restored to this state later.
class Memento
{
string name;
string phoneNumber;
public:
Memento() {}
Memento(string nameStr, string pNumberStr)
{
name = nameStr;
phoneNumber = pNumberStr;
}
string getName()
{
return name;
}
string getPhoneNumber()
{
return phoneNumber;
}
};
class careTaker
{
public:
Memento objMemento;
};
class Originator
{
string name;
string phoneNumber;
public:
Originator(string nameStr, string pNumberStr)
{
setValue(nameStr, pNumberStr);
}
void setValue(string nameStr, string pNumberStr)
{
name = nameStr;
phoneNumber = pNumberStr;
}
Memento SaveMemento()
{
Memento temp(name, phoneNumber);
return temp;
}
void RestoreMemento(Memento temp)
{
name = temp.getName();
phoneNumber = temp.getPhoneNumber();
}
void Display()
{
cout << "Name : " << name << endl;
cout << "PhoneNumber : " << phoneNumber << endl;
}
};
void Originator_Memento()
{
careTaker ct;
Originator ot("anitha", "234234889");
ot.Display();
cout << endl;
ct.objMemento = ot.SaveMemento();
ot.setValue("ani", "19383948");
ot.Display();
cout << endl;
ot.RestoreMemento(ct.objMemento);
ot.Display();
}
7) Observer:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
class Observer
{
public:
virtual void update() = 0;
};
class Subject
{
list<Observer*> list_Observer;
list<Observer*>::iterator it;
public:
void addObserver(Observer* obj)
{
list_Observer.push_back(obj);
}
void delObserver(Observer* obj)
{
list_Observer.remove(obj);
}
void Notify()
{
for (it = list_Observer.begin(); it != list_Observer.end(); it++)
{
(*it)->update();
}
}
};
class ConcreteSubject : public Subject
{
public:
static string subjectState;
ConcreteSubject() {}
};
string ConcreteSubject::subjectState = "";
class ConcreteObserver : public Observer
{
string observerName;
string observerState;
ConcreteSubject objConSubject;
public:
ConcreteObserver(string obName, ConcreteSubject obj)
{
observerName = obName;
objConSubject = obj;
}
void update()
{
observerState = objConSubject.subjectState;
cout << "ConcreteObserver::update" << endl;
cout << "ObserverName : " << observerName.c_str() << endl;
cout << "ObserverState :" << observerState.c_str() << endl;
cout << endl;
}
};
void Observer_State()
{
ConcreteSubject objConSub;
Observer* ptr_Observer = new ConcreteObserver("X", objConSub);
Observer* ptr_Observer1 = new ConcreteObserver("Y", objConSub);
objConSub.addObserver(ptr_Observer);
objConSub.addObserver(ptr_Observer1);
objConSub.subjectState = "ABC";
objConSub.Notify();
objConSub.subjectState = "DEF";
objConSub.Notify();
objConSub.subjectState = "GHI";
objConSub.Notify();
}
8) State:
a) Allow an object to alter its behaviour when its internal state changes.
b) The object will appear to change its class.
Example:
class abs_state
{
public:
virtual void func1() = 0;
virtual void func2() = 0;
};
class abs_implementation1 : public abs_state
{
public:
void func1()
{
cout << "abs_implementation1::func1" << endl;
}
void func2()
{
cout << "abs_implementation1::func2" << endl;
}
};
class abs_implementation2 : public abs_state
{
public:
void func1()
{
cout << "abs_implementation2::func1" << endl;
}
void func2()
{
cout << "abs_implementation2::func2" << endl;
}
};
class abs_surrogate_state : public abs_state
{
abs_state* ptr_state;
public:
abs_surrogate_state(abs_state* ptr)
{
ptr_state = ptr;
}
void change_impl(abs_state* ptr)
{
ptr_state = ptr;
}
void func1()
{
ptr_state->func1();
}
void func2()
{
ptr_state->func2();
}
};
void abs_surrogate_state_Function()
{
abs_surrogate_state* ptr_state = new abs_surrogate_state(new abs_implementation1);
ptr_state->func1();
ptr_state->func2();
cout << endl;
ptr_state->change_impl(new abs_implementation2);
ptr_state->func1();
ptr_state->func2();
}
a) Define a family of algorithms, encapsulate each one, and make them interchangeable.
b) Strategy lets the algorithm vary independently from clients that use it.
class Strategy
{
public:
virtual void AlgorithmInterface() = 0;
};
class ConcreteStrategyA : public Strategy
{
public:
void AlgorithmInterface()
{
cout << "ConcreteStrategyA::AlgorithmInterface" << endl;
}
};
class ConcreteStrategyB : public Strategy
{
public:
void AlgorithmInterface()
{
cout << "ConcreteStrategyB::AlgorithmInterface" << endl;
}
};
class ConcreteStrategyC : public Strategy
{
public:
void AlgorithmInterface()
{
cout << "ConcreteStrategyC::AlgorithmInterface" << endl;
}
};
class Context
{
Strategy* strat;
public:
Context(Strategy* st)
{
strat = st;
}
void ContextInterface()
{
strat->AlgorithmInterface();
}
};
void Context_Strategy()
{
Context* c1 = new Context(new ConcreteStrategyA);
Context* c2 = new Context(new ConcreteStrategyB);
Context* c3 = new Context(new ConcreteStrategyC);
c1->ContextInterface();
c2->ContextInterface();
c3->ContextInterface();
}
10) Template:
a) Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.
b) Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
Example:
class AbstractClass
{
public:
virtual void PrimitiveOperation1() = 0;
virtual void PrimitiveOperation2() = 0;
void TemplateMethod()
{
PrimitiveOperation1();
PrimitiveOperation2();
}
};
class ConcreteClassA : public AbstractClass
{
public:
void PrimitiveOperation1()
{
cout << "ConcreteClassA::PrimitiveOperation1" << endl;
}
void PrimitiveOperation2()
{
cout << "ConcreteClassA::PrimitiveOperation2" << endl;
}
};
class ConcreteClassB : public AbstractClass
{
public:
void PrimitiveOperation1()
{
cout << "ConcreteClassB::PrimitiveOperation1" << endl;
}
void PrimitiveOperation2()
{
cout << "ConcreteClassB::PrimitiveOperation2" << endl;
}
};
void Concrete_Abstract()
{
AbstractClass* abs_A = new ConcreteClassA();
abs_A->TemplateMethod();
cout << endl;
AbstractClass* abs_B = new ConcreteClassB();
abs_B->TemplateMethod();
}
a) Represent an operation to be performed on the elements of an object structure.
b) Visitor allows one to define a new operation without changing the classes of the elements on which it operates.
class Visitor;
class Element
{
public:
virtual void Accept(Visitor* visitor) = 0;
virtual void Operation() = 0;
};
class ConcreteElementA : public Element
{
public:
void Accept(Visitor* visitor)
{
cout << "ConcreteElementA::Accept" << endl;
}
void Operation()
{
cout << "ConcreteElementA::Operation" << endl;
}
};
class ConcreteElementB : public Element
{
public:
void Accept(Visitor* visitor)
{
cout << "ConcreteElementB::Accept" << endl;
}
void Operation()
{
cout << "ConcreteElementB::Operation" << endl;
}
};
class ObjectStructure
{
list<Element*> list_Elements;
list<Element*>::iterator it;
public:
void AddToList(Element* e)
{
list_Elements.push_back(e);
}
void RemoveToList(Element* e)
{
list_Elements.remove(e);
}
void traverseElements(Visitor* v)
{
for (it = list_Elements.begin(); it != list_Elements.end(); it++)
{
(*it)->Accept(v);
}
}
};
class Visitor
{
public:
Visitor(){}
virtual void visitConcreteElementA(ConcreteElementA* ceA) = 0;
virtual void visitConcreteElementB(ConcreteElementB* ceB) = 0;
};
class ConcreteVisitorA : public Visitor
{
public:
ConcreteVisitorA() {}
void visitConcreteElementA(ConcreteElementA* ceA)
{
ceA->Operation();
}
void visitConcreteElementB(ConcreteElementB* ceB)
{
ceB->Operation();
}
};
class ConcreteVisitorB : public Visitor
{
public:
ConcreteVisitorB() {}
void visitConcreteElementA(ConcreteElementA* ceA)
{
ceA->Operation();
}
void visitConcreteElementB(ConcreteElementB* ceB)
{
ceB->Operation();
}
};
void Visitor_Element()
{
ObjectStructure obj_Structure;
obj_Structure.AddToList(new ConcreteElementA);
obj_Structure.AddToList(new ConcreteElementB);
Visitor* v1 = new ConcreteVisitorA();
Visitor* v2 = new ConcreteVisitorB();
obj_Structure.traverseElements(v1);
obj_Structure.traverseElements(v2);
}