Behavioural Design Patterns
Behavioural Design Patterns
Intent
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified
and updated automatically.
Encapsulate the core (or common or engine) components in a Subject abstraction, and the variable (or optional or user
interface) components in an Observer hierarchy.
The "View" part of Model-View-Controller.
The Observer defines a one-to-many relationship so that when one object changes state, the others are notified and
updated automatically. Some auctions demonstrate this pattern. Each bidder possesses a numbered paddle that is used to
indicate a bid. The auctioneer starts the bidding, and "observes" when a paddle is raised to accept the bid. The acceptance
of the bid changes the bid price which is broadcast to all of the bidders in the form of a new bid.
Page 2 of 21
Check list
1. Differentiate between the core (or independent) functionality and the optional (or dependent) functionality.
2. Model the independent functionality with a "subject" abstraction.
3. Model the dependent functionality with an "observer" hierarchy.
4. The Subject is coupled only to the Observer base class.
5. The client configures the number and type of Observers.
6. Observers register themselves with the Subject.
7. The Subject broadcasts events to all registered Observers.
8. The Subject may "push" information at the Observers, or, the Observers may "pull" the information they need from the
Subject.
Example in Java
abstract class Observer {
protected Subject subj;
public abstract void update();
}
class Subject {
private Observer[] observers = new Observer[9];
private int totalObs = 0;
private int state;
public void attach( Observer o ) {
observers[totalObs++] = o;
}
Example in C#
using System;
using System.Collections;
class MainApp
{
static void Main()
{
// Configure Observer pattern
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s,"X"));
s.Attach(new ConcreteObserver(s,"Y"));
s.Attach(new ConcreteObserver(s,"Z"));
// "Subject"
abstract class Subject
{
private ArrayList observers = new ArrayList();
// "ConcreteSubject"
class ConcreteSubject : Subject
Page 4 of 21
{
private string subjectState;
// Property
public string SubjectState
{
get{ return subjectState; }
set{ subjectState = value; }
}
}
// "Observer"
abstract class Observer
{
public abstract void Update();
}
// "ConcreteObserver"
class ConcreteObserver : Observer
{
private string name;
private string observerState;
private ConcreteSubject subject;
// Constructor
public ConcreteObserver(
ConcreteSubject subject, string name)
{
this.subject = subject;
this.name = name;
}
// Property
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
}
Observer X's new state is ABC
Observer Y's new state is ABC
Observer Z's new state is ABC
Page 5 of 21
Participants
Context (Account)
o defines the interface of interest to clients
o maintains an instance of a ConcreteState subclass that defines the current state.
State (State)
o defines an interface for encapsulating the behavior associated with a particular state of the Context.
Concrete State (RedState, SilverState, GoldState)
o each subclass implements a behavior associated with a state of Context
Structural code in C#
This structural code demonstrates the State pattern which allows an object to behave differently depending on its internal
state. The difference in behavior is delegated to objects that represent this state.
using System;
namespace DoFactory.GangOfFour.State.Structural
{
/// <summary>
/// MainApp startup class for Structural
/// State Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
// Setup context in a state
Context c = new Context(new ConcreteStateA());
/// <summary>
/// A 'ConcreteState' class
/// </summary>
class ConcreteStateA : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateB();
} }
/// <summary>
/// A 'ConcreteState' class
/// </summary>
class ConcreteStateB : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateA();
} }
/// <summary>
/// The 'Context' class
/// </summary>
class Context
{
private State _state;
// Constructor
public Context(State state)
{
this.State = state;
}
Output
State: ConcreteStateA
State: ConcreteStateB
State: ConcreteStateA
State: ConcreteStateB
State: ConcreteStateA
Page 7 of 21
Intent
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary
independently from clients that use it.
Implementation
Strategy - defines an interface common to all supported algorithms. Context uses this interface to call the algorithm defined by a
ConcreteStrategy.
Context
The Context objects contains a reference to the ConcreteStrategy that should be used. When an operation is required then the
algorithm is run from the strategy object. The Context is not aware of the strategy implementation. If necessary, addition objects
can be defined to pass data from context object to strategy.
The context object receives requests from the client and delegates them to the strategy object. Usually the ConcreteStartegy is
created by the client and passed to the context. From this point the clients interacts only with the context.
Let's consider an application used to simulate and study robots interaction. For the beginning a simple application is created to
simulate an arena where robots are interacting. We have the following classes:
Conctete Strategies: AggressiveBehaviour, DefensiveBehaviour, NormalBehaviour; each of them defines a specific behavior. In
order to decide the action this class needs information that is passed from robot sensors like position, close obstacles, etc.
Robot - The robot is the context class. It keeps or gets context information such as position, close obstacles, etc, and passes
necessary information to the Strategy class.
In the main section of the application the several robots are created and several different behaviors are created. Each robot has a
different behavior assigned: 'Big Robot' is an aggressive one and attacks any other robot found, 'George v.2.1' is really scared and
run away in the opposite direction when it encounter another robot and 'R2' is pretty calm and ignore any other robot. At some
point the behaviors are changed for each robot.
r1.setBehaviour(new AgressiveBehaviour());
r2.setBehaviour(new DefensiveBehaviour());
r3.setBehaviour(new NormalBehaviour());
r1.move();
r2.move();
r3.move();
r1.setBehaviour(new DefensiveBehaviour());
r2.setBehaviour(new AgressiveBehaviour());
r1.move();
r2.move();
r3.move();
}
}
When data should be passed the drawbacks of each method should be analyzed. For example, if some classes are created to
encapsulate additional data, a special care should be paid to what fields are included in the classes. Maybe in the current
implementation all required fields are added, but maybe in the future some new strategy concrete classes require data from
context which are not include in additional classes. Another fact should be specified at this point: it's very likely that some of the
strategy concrete classes will not use field passed to the in the additional classes.
On the other side, if the context object is passed to the strategy then we have a tighter coupling between strategy and context.
This real-world code demonstrates the Strategy pattern which encapsulates sorting algorithms in the form of sorting
objects. This allows clients to dynamically change sorting strategies including Quicksort, Shellsort, and Mergesort.
1. using System;
2. using System.Collections.Generic;
3. namespace DoFactory.GangOfFour.Strategy.RealWorld
4. { /// <summary>
5. /// MainApp startup class for Real-World
6. /// Strategy Design Pattern.
7. /// </summary>
8. class MainApp
9. {
10. /// <summary>
11. /// Entry point into console application.
12. /// </summary>
13. static void Main()
14. {
15. // Two contexts following different strategies
16. SortedList studentRecords = new SortedList();
17.
18. studentRecords.Add("Samual");
19. studentRecords.Add("Jimmy");
20. studentRecords.Add("Sandra");
21. studentRecords.Add("Vivek");
22. studentRecords.Add("Anna");
23.
24. studentRecords.SetSortStrategy(new QuickSort());
25. studentRecords.Sort();
26.
27. studentRecords.SetSortStrategy(new ShellSort());
28. studentRecords.Sort();
29.
30. studentRecords.SetSortStrategy(new MergeSort());
31. studentRecords.Sort();
32.
33. // Wait for user
34. Console.ReadKey();
35. }
36. }
37.
38. /// <summary>
39. /// The 'Strategy' abstract class
40. /// </summary>
41. abstract class SortStrategy
42. { public abstract void Sort(List<string> list); }
43.
44. /// <summary>
45. /// A 'ConcreteStrategy' class
46. /// </summary>
47. class QuickSort : SortStrategy
48. {
49. public override void Sort(List<string> list)
50. {
51. list.Sort(); // Default is Quicksort
52. Console.WriteLine("QuickSorted list ");
53. } }
54.
55. /// <summary>
56. /// A 'ConcreteStrategy' class
57. /// </summary>
58. class ShellSort : SortStrategy
59. {
60. public override void Sort(List<string> list)
61. {
62. //list.ShellSort(); not-implemented
63. Console.WriteLine("ShellSorted list ");
64. } }
65.
Page 12 of 21
66. /// <summary>
67. /// A 'ConcreteStrategy' class
68. /// </summary>
69. class MergeSort : SortStrategy
70. {
71. public override void Sort(List<string> list)
72. {
73. //list.MergeSort(); not-implemented
74. Console.WriteLine("MergeSorted list ");
75. } }
76.
77. /// <summary>
78. /// The 'Context' class
79. /// </summary>
80. class SortedList
81. {
82. private List<string> _list = new List<string>();
83. private SortStrategy _sortstrategy;
84.
85. public void SetSortStrategy(SortStrategy sortstrategy)
86. {
87. this._sortstrategy = sortstrategy;
88. }
89.
90. public void Add(string name)
91. {
92. _list.Add(name);
93. }
94.
95. public void Sort()
96. {
97. _sortstrategy.Sort(_list);
98.
99. // Iterate over list and display results
100. foreach (string name in _list)
101. {
102. Console.WriteLine(" " + name);
103. }
104. Console.WriteLine();
105. } }}
106.
Output
QuickSorted list
Anna
Jimmy
Samual
Sandra
Vivek
ShellSorted list
Anna
Jimmy
Samual
Sandra
Vivek
MergeSorted list
Anna
Jimmy
Samual
Sandra
Vivek
Page 13 of 21
Template means Preset format like HTML templates which have a fixed preset format. Similarly in the template method
pattern, we have a preset structure method called template method which consists of steps. These steps can be an abstract
method which will be implemented by its subclasses.
So in short you can say, in the template method pattern, there is a template method which defines a set of steps and the
implementation of steps can be deferred to subclasses. Thus a template method defines an algorithm but the exact steps can
be defined in subclasses.
So in the above diagram, as you can see we have defined a template method with three steps: operation1, operation2, and
operation3. Among them, opeation1 and operation2 are abstract steps, so these are implemented byConcreteClass. We
have implemented operation3 here. You can implement an operation in a base class in two scenarios: first is if it is common to
all, and second is if it is the default implementation of that method. The UML diagram will be much clearer now.
Page 14 of 21
Components:
AbstractClass
It implements an abstract operation of a super class to carry out subclass specific steps of the algorithm and also overrides an
operation if the default behavior is not required
Important points about template method pattern:
The template method in a super class follows “the Hollywood principle”: “Don't call us, we'll call you”. This refers to the fact
that instead of calling the methods from the base class in the subclasses, the methods from the subclass are called in the
template method from the superclass.
Template method in the super class should not be overridden so make it final
Customization hooks: Methods containing a default implementation that may be overridden in other classes are called hook
methods. Hook methods are intended to be overridden, concrete methods are not. So in this pattern, we can provide hook
methods. The problem is sometimes it becomes very hard to differentiate between hook methods and concrete methods.
Template methods are techniques for code reuse because with this, you can figure out a common behavior and defer specific
behavior to subclasses.
Example
Let's take an example. When you have to read from two data sources, e.g., CSV and database, then you have to process that
data and generate the output as CSV files. Here three steps are involved.
Read data from the corresponding data source
Process data
Write output to CSV files
Page 15 of 21
Java code
The class below contains a template method called parseDataAndGenerateOutput which consists of steps for reading data,
processing data, and writing to a CSV file.
1.DataParser.java
package org.arpit.javapostsforlearning;
abstract public class DataParser {
//Template method
//This method defines a generic structure for parsing data
public void parseDataAndGenerateOutput()
{
readData();
processData();
writeData();
}
//This methods will be implemented by its subclass
abstract void readData();
abstract void processData();
//We have to write output in a CSV file so this step will be same for all subclasses
public void writeData()
{
System.out.println("Output generated,writing to CSV");
}
}
In the below class, CSV specific steps are implemented in this class.
2.CSVDataParser.java
package org.arpit.javapostsforlearning;
public class CSVDataParser extends DataParser {
void readData() {
System.out.println("Reading data from csv file");
}
void processData() {
System.out.println("Looping through loaded csv file");
}
}
3. DatabaseDataParser.java
package org.arpit.javapostsforlearning;
public class DatabaseDataParser extends DataParser {
void readData() {
System.out.println("Reading data from database");
}
void processData() {
System.out.println("Looping through datasets");
}
}
4. TemplateMethodMain.java
package org.arpit.javapostsforlearning;
public class TemplateMethodMain {
/**
* @author arpit mandliya
*/
public static void main(String[] args) {
Output:
definition
Avoid coupling 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.
participants
Handler (Approver)
o defines an interface for handling the requests
o (optional) implements the successor link
ConcreteHandler (Director, VicePresident, President)
o handles requests it is responsible for
o can access its successor
o if the ConcreteHandler can handle the request, it does so; otherwise it forwards the request to its successor
Client (ChainApp)
o initiates the request to a ConcreteHandler object on the chain
Lets start by looking at the Handler abstract class i.e. Employee class.
Now since our Handler class is ready, lets look at the ConcreteHandlers one by one. Lets start with TeamLeaderclass.
Checking of this class could take the action i.e. leave applied is less than 10 days.
If this class could take the action then show the response to the user.
Page 19 of 21
If this class is not able to take the action then pass on the request to the ProjectLeader class i.e. its successor.
Checking of this class could take the action i.e. leave applied is less than 20 days.
If this class could take the action then show the response to the user.
If this class is not able to take the action then pass on the request to the HR class i.e. its successor.
class HR : Employee
{
const int MAX_LEAVES_CAN_APPROVE = 30;
Checking of this class could take the action i.e. leave applied is less than 30 days.
If this class could take the action then show the response to the user.
If this class is not able to take the action then let the user know that he needs to have a manual discussion and his request has
been suspended.
The actual action item i.e. the leave is encapsulated into a class for better modularity, so before running the application lets
see how this Leave class looks like
Guid leaveID;
And finally we need the Client that will set the successor chain and initiate the request.
class Program
{
static void Main(string[] args)
{
// lets create employees
Page 21 of 21
TeamLeader tl = new TeamLeader();
ProjectLeader pl = new ProjectLeader();
HR hr = new HR();
Console.ReadLine();
}
}
So we can see that this Main function is creating the chain by setting the successors for each class and is initiating the request
to TeamLeader class. One request for each scenario has been made. When we run this application.
So we can see that each request get passed on and processed by the respective class based on the number of days applied
for. Before wrapping up let us look at the class diagram for our application and compare it with the original GoF diagram.