Behavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.
Behavioural Patterns
- Mediator:- Defines simplified communication between classes.
- Memento:-Capture and restore an object’s internal state.
- Interpreter: – A way to include language elements in a program.
- Iterator:-Sequentially access the elements of a collection.
- Chain of Resp: – A way of passing a request between a chain of objects.
- Command:-Encapsulate a command request as an object.
- State:-Alter an object’s behavior when its state changes.
- Strategy:-Encapsulates an algorithm inside a class.
- Observer: – A way of notifying change to a number of classes.
- Template Method:- Defer the exact steps of an algorithm to a subclass.
- Visitor:- Defines a new operation to a class without change.
Many a times in projects communication between components are complex. Due to this the logic between the components becomes very complex. Mediator pattern helps the objects to communicate in a disassociated manner, which leads to minimizing complexity.Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
Example : The classes and/or objects participating in this pattern are:
- Mediator (IChatroom)
- defines an interface for communicating with Colleague objects
- ConcreteMediator (Chatroom)
- implements cooperative behavior by coordinating Colleague objects
- knows and maintains its colleagues
- Colleague classes (Participant)
- each Colleague class knows its Mediator object
- each colleague communicates with its mediator whenever it would have otherwise communicated with another colleague
interface IChatroom { void Send(string message, Colleague participant); } class Chatroom : IChatroom { Colleague colleague1; Colleague colleague2; public Colleague Colleague1 { set { colleague1 = value; } } public Colleague Colleague2 { set { colleague2 = value; } } public void Send(string message, Colleague colleague) { if (colleague == colleague1) { colleague2.Notify(message); } else { colleague1.Notify(message); } } } abstract class Participant { protected IChatroom mediator; string name; // Constructor public Participant(string Name, IChatroom mediator) { this.mediator = mediator; this.name = Name; } public string Name { get { return this.name; } } } class Colleague:Participant { public Colleague(string Name, IChatroom mediator) : base(Name, mediator) { } public void Send(string message) { mediator.Send(message, this); } public void Notify(string message) { Console.WriteLine( this.Name + " gets message: " + message); } } //Application Chatroom room = new Chatroom(); Colleague c1 = new Colleague("Rajneesh Noonia", room); Colleague c2 = new Colleague("Robert", room); room.Colleague1 = c1; room.Colleague2 = c2; c1.Send("How are you?"); c2.Send("Fine, thanks");
Memento pattern is the way to capture objects internal state with out violating encapsulation. Memento pattern helps us to store a snapshot which can be reverted at any moment of time by the object. Let’s understand what it means in practical sense. Consider ‘Memento practical example’, it shows a customer screen. Let’s say if the user starts editing a customer record and he makes some changes. Later he feels that he has done something wrong and he wants to revert back to the original data. This is where memento comes in to play. It will help us store a copy of data and in case the user presses cancel the object restores to its original state.The memento pattern is used by two objects: the originator and a caretaker. The originator is some object that has an internal state. The caretaker is going to do something to the originator, but wants to be able to undo the change. The caretaker first asks the originator for a memento object. Then it does whatever operation (or sequence of operations) it was going to do. To roll back to the state before the operations, it returns the memento object to the originator. The memento object itself is an opaque object (one which the caretaker cannot, or should not, change). When using this pattern, care should be taken if the originator may change other objects or resources – the memento pattern operates on a single object.
Example :
// The 'Originator' class class Originator { private string _state; // Property public string State { get { return _state; } set { _state = value; Console.WriteLine("State = " + _state); } } // Creates memento public Memento CreateMemento() { return (new Memento(_state)); } // Restores original state public void SetMemento(Memento memento) { Console.WriteLine("Restoring state..."); State = memento.State; } } // The 'Memento' class class Memento { private string _state; // Constructor public Memento(string state) { this._state = state; } // Gets or sets state public string State { get { return _state; } } } // The 'Caretaker' class class Caretaker { private Memento _memento; // Gets or sets memento public Memento Memento { set { _memento = value; } get { return _memento; } } } //Application Originator o = new Originator(); o.State = "On"; // Store internal state Caretaker c = new Caretaker(); c.Memento = o.CreateMemento(); // Continue changing originator o.State = "Off"; // Restore saved state o.SetMemento(c.Memento);
Interpreter pattern allows us to interpret grammar in to code solutions. Ok, what does that mean ?. Grammars are mapped to classes to arrive to a solution. For instance 7 – 2 can be mapped to ‘Minus’ class. In one line interpreter pattern gives us the solution of how to write an interpreter which can read a grammar and execute the same in the code. The interpreter pattern specifies how to evaluate sentences in a language. The basic idea is to have a class for each symbol (terminal or nonterminal) in a specialized computer language. The syntax tree of a sentence in the language is an instance of the composite pattern and is used to evaluate (interpret) the sentence.
Example :
interface IExpression { int Interpret(Dictionary variables); } class Number : IExpression { public int number; public Number(int number) { this.number = number; } public int Interpret(Dictionary<string, int> variables) { return number; } } abstract class BasicOperation : IExpression { IExpression leftOperator, rightOperator; protected BasicOperation() { } public BasicOperation(IExpression left, IExpression right) { leftOperator = left; rightOperator = right; } public int Interpret(Dictionary<string, int> variables) { return Execute(leftOperator.Interpret(variables), rightOperator.Interpret(variables)); } abstract protected int Execute(int left, int right); } class Plus : BasicOperation { public Plus(IExpression left, IExpression right) : base(left, right) { } protected override int Execute(int left, int right) { return left + right; } } class Minus : BasicOperation { public Minus(IExpression left, IExpression right) : base(left, right) { } protected override int Execute(int left, int right) { return left - right; } } class Variable : IExpression { private string name; public Variable(string name) { this.name = name; } public int Interpret(Dictionary<string, int> variables) { return variables[name]; } } class Evaluator { private IExpression syntaxTree; public Evaluator(string expression) { Stack<IExpression> stack = new Stack<IExpression>(); foreach (string token in expression.Split(' ')) { if (token.Equals("+")) stack.Push(new Plus(stack.Pop(), stack.Pop())); else if (token.Equals("-")) stack.Push(new Minus(stack.Pop(), stack.Pop())); else stack.Push(new Variable(token)); } syntaxTree = stack.Pop(); } public int Evaluate(Dictionary<string, int> context) { return syntaxTree.Interpret(context); } } //Application Evaluator evaluator = new Evaluator("w x z - +"); Dictionary<string, int> values = new Dictionary<string,int>(); values.Add("w", 5); values.Add("x", 8); values.Add("z", 15); Console.WriteLine(evaluator.Evaluate(values));
Iterator pattern allows sequential access of elements with out exposing the inside code. Let’s understand what it means. Let’s say you have a collection of records which you want to browse sequentially and also maintain the current place which recordset is browsed, then the answer is iterator pattern. It’s the most common and unknowingly used pattern. Whenever you use a ‘foreach’ (It allows us to loop through a collection sequentially) loop you are already using iterator pattern to some extent.
Example :
public class Employee{ private int m_nID; private string m_strName; public Employee(int nID, string strName){ m_nID = nID; m_strName = strName; } public int EmployeeID{get{return this.m_nID;}} public string EmployeeName{get{return this.m_strName;}} } public class EnumerateEmployee: IEnumerator { private int m_nPosition; private ArrayList m_ArrEmployee = new ArrayList(); public EnumerateEmployee(){ m_nPosition = -1; m_ArrEmployee.Add(new Employee(1,"Kamsa")); m_ArrEmployee.Add(new Employee(2,"Rama")); m_ArrEmployee.Add(new Employee(3,"Sita")); m_ArrEmployee.Add(new Employee(4,"Gopala")); } public bool MoveNext(){ bool b_return = false; ++m_nPosition; if(m_nPosition < m_ArrEmployee.Count) b_return = true; return b_return; } public object Current {get{return m_ArrEmployee[m_nPosition];}} public void Reset(){m_nPosition = -1;} } //Application string strName; int nID; EmployeeList objEmpList = new EmployeeList(); IEnumerator objEnumEmp = objEmpList.GetEnumerator(); while(objEnumEmp.MoveNext()) { Employee objEmployee = (Employee)objEnumEmp.Current; nID = objEmployee.EmployeeID; strName = objEmployee.EmployeeName; }
Chain of responsibility is used when we have series of processing which will be handled by a series of handler logic. There are situations when a request is handled by series of handlers. So the request is taken up by the first handler, he either can handle part of it or can not, once done he passes to the next handler down the chain. This goes on until the proper handler takes it up and completes the processing. Example :
class Purchase { public int Number { get; set; } public double Amount { get; set; } public string Description { get; set; } public Purchase(int Number, double Amount, string Description) { this.Number = Number; this.Amount = Amount; this.Description = Description; } } abstract class Approver { protected Approver(Approver Successor) { this.Successor = Successor; } protected Approver Successor { get; private set; } public abstract void ProcessRequest(Purchase purchase); } //Various Approvers (request handlers) class Director : Approver { public Director(Approver Successor):base(Successor){} public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 10000.0) { Console.WriteLine("{0} approved request# {1}",this.GetType().Name, purchase.Number); } else if (Successor != null) { Successor.ProcessRequest(purchase); } } } class VicePresident : Approver { public VicePresident(Approver Successor) : base(Successor) { } public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 25000.0) { Console.WriteLine("{0} approved request# {1}",this.GetType().Name, purchase.Number); } else if (Successor != null) { Successor.ProcessRequest(purchase); } } } class President : Approver { public President(Approver Successor) : base(Successor) { } public override void ProcessRequest(Purchase purchase) { if (purchase.Amount < 100000.0) { Console.WriteLine("{0} approved request# {1}",this.GetType().Name, purchase.Number); } else { Console.WriteLine("Request# {0} requires an executive meeting!",purchase.Number); } } } //Application // Setup Chain of Responsibility Approver director = new Director(null); Approver vicePresident = new VicePresident(director); Approver president = new President(vicePresident); // Generate and process purchase requests Purchase p = new Purchase(2034, 350.00, "Assets"); director.ProcessRequest(p); p = new Purchase(2035, 32590.10, "Project X"); director.ProcessRequest(p); p = new Purchase(2036, 122100.00, "Project Y"); director.ProcessRequest(p);
Command pattern allows a request to exist as an object. The command pattern is a design pattern in which an object is used to represent and encapsulate all the information needed to call a method at a later time. This information includes the method name, the object that owns the method and values for the method parameters.
Three terms always associated with the command pattern are client, invoker and receiver. The client instantiates the command object and provides the information required to call the method at a later time. The invoker decides when the method should be called. The receiver is an instance of the class that contains the method’s code.
Using command objects makes it easier to construct general components that need to delegate, sequence or execute method calls at a time of their choosing without the need to know the owner of the method or the method parameters.
Example :
State pattern allows an object to change its behavior depending on the current values of the object. Consider the ‘State pattern example’. It’s an example of a bulb operation. If the state of the bulb is off and you press the switch the bulb will turn off. If the state of bulb is on and you press the switch the bulb will be off. So in short depending on the state the behavior changes. Example :
Strategy pattern are algorithms inside a class which can be interchanged depending on the class used. This pattern is useful when you want to decide on runtime which algorithm to be used.
Example :
Observer pattern helps us to communicate between parent class and its associated or dependent classes. There are two important concepts in observer pattern ‘Subject’ and ‘Observers’. The subject sends notifications while observers receive notifications if they are registered with the subject. Example :
In template pattern we have an abstract class which acts as a skeleton for its inherited classes. The inherited classes get the shared functionality. The inherited classes take the shared functionality and add enhancements to the existing functionality. In word or power point how we take templates and then prepare our own custom presentation using the base. Template classes works on the same fundamental.
Example :
Visitor pattern allows us to change the class structure with out changing the actual class. Its way of separating the logic and algorithm from the current data structure. Due to this you can add new logic to the current data structure with out altering the structure. Second you can alter the structure with out touching the logic. Example :
*Visitor and strategy look very much similar as they deal with encapsulating complex logic from data. We can say visitor is more general form of strategy.