Chain of Responsibility Method Design Pattern
The Chain of Responsibility pattern is a behavioral design pattern that allows an object to pass requests along a chain of potential handlers until one of them handles the request. This pattern decouples the sender of the request from its receivers, giving more than one object the chance to handle the request. It enhances flexibility in assigning responsibilities to objects & simplifies your code.
When to use this :
-
When you want to pass a request along a chain of potential handlers without knowing which handler will process the request.
-
When you want to decouple the sender of a request from its receivers.
- When multiple objects should have the opportunity to handle the request.
Example
Java
abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(String request);
}
class ConcreteHandler1 extends Handler {
public void handleRequest(String request) {
if (request.equals("Low")) {
System.out.println("ConcreteHandler1 handled the request.");
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
class ConcreteHandler2 extends Handler {
public void handleRequest(String request) {
if (request.equals("High")) {
System.out.println("ConcreteHandler2 handled the request.");
} else if (successor != null) {
successor.handleRequest(request);
}
}
}
public class Client {
public static void main(String[] args) {
Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
h1.setSuccessor(h2);
h1.handleRequest("Low");
h1.handleRequest("High");
}
}

You can also try this code with Online Java Compiler
Run Code
Output
ConcreteHandler1 handled the request.
ConcreteHandler2 handled the request.
In this Java example, ConcreteHandler1 & ConcreteHandler2 are different handlers in the chain that process the request based on their capability. If one handler cannot process the request, it passes it to the next handler in the chain.
Command Method Design Pattern
The Command pattern is a behavioral design pattern that turns a request into a stand-alone object containing all information about the request. This transformation allows you to parameterize methods with different requests, delay or queue a request’s execution, and support undoable operations. Essentially, it decouples the object that sends the request from the one that knows how to execute it.
When to use this :
-
When you need to parameterize objects according to an action to perform.
-
When you need to queue operations, schedule their execution, or execute them remotely.
- When you need to implement reversible operations.
Example
Java
interface Command {
void execute();
}
class Light {
public void turnOn() {
System.out.println("Light is on.");
}
public void turnOff() {
System.out.println("Light is off.");
}
}
class TurnOnCommand implements Command {
private Light light;
public TurnOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOn();
}
}
class TurnOffCommand implements Command {
private Light light;
public TurnOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.turnOff();
}
}
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
public class Client {
public static void main(String[] args) {
Light light = new Light();
Command turnOn = new TurnOnCommand(light);
Command turnOff = new TurnOffCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(turnOn);
remote.pressButton();
remote.setCommand(turnOff);
remote.pressButton();
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Light is on.
Light is off.
In this Java example, Light is a receiver that has the actual operations (turnOn & turnOff), while TurnOnCommand & TurnOffCommand are the commands that encapsulate these operations. The RemoteControl acts as an invoker, using these commands to execute the operations.
Interpreter Method Design Pattern
The Interpreter pattern is a behavioral design pattern that defines a grammatical representation for a language and provides an interpreter to deal with this grammar. This pattern is used for designing specific types of language processing, allowing easy interpretation of sentences in the language by matching the patterns.
When to use this :
-
When there is a language to interpret, and you can represent statements in this language as abstract syntax trees.
-
When the grammar of the language is simple, for complex grammars, the class hierarchy for the grammar becomes large and unmanageable.
- For frequently used grammars, interpreting the grammar can be more efficient than repeatedly parsing it.
Example
Java
interface Expression {
boolean interpret(String context);
}
class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data){
this.data = data;
}
public boolean interpret(String context) {
return context.contains(data);
}
}
class OrExpression implements Expression {
private Expression expr1;
private Expression expr2;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
class AndExpression implements Expression {
private Expression expr1;
private Expression expr2;
public AndExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
public boolean interpret(String context) {
return expr1.interpret(context) && expr2.interpret(context);
}
}
public class InterpreterClient {
public static void main(String[] args) {
Expression person1 = new TerminalExpression("Gaurav");
Expression person2 = new TerminalExpression("Rinki");
Expression isSingle = new OrExpression(person1, person2);
System.out.println("Gaurav is single? " + isSingle.interpret("Gaurav"));
System.out.println("Rinki and Gaurav are single? " + new AndExpression(person1, person2).interpret("Gaurav Rinki"));
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Gaurav is single? true
Rinki and Gaurav are single? true
In this Java example, TerminalExpression, OrExpression, and AndExpression are different types of expressions that interpret whether given data matches certain criteria. The InterpreterClient uses these expressions to interpret sentences.
Mediator Method Design Pattern
The Mediator pattern is a behavioral design pattern that reduces complex communication between multiple objects or classes by introducing a mediator object. This mediator handles all the communications between different objects, making it easier to manage without them needing to refer to each other explicitly. This leads to less coupled systems where components are more manageable and easier to understand.
When to use this :
-
When a set of objects communicate in well-defined but complex ways, creating interdependencies between them.
-
When you want to reduce the direct communications between objects and instead force them to collaborate only via a mediator object.
- When reusability of an object is a concern, and you want to keep objects loosely coupled.
Example
Java
import java.util.ArrayList;
import java.util.List;
interface Mediator {
void sendMessage(String message, Colleague colleague);
void addColleague(Colleague colleague);
}
class ConcreteMediator implements Mediator {
private List<Colleague> colleagues;
public ConcreteMediator() {
this.colleagues = new ArrayList<>();
}
public void addColleague(Colleague colleague) {
colleagues.add(colleague);
}
public void sendMessage(String message, Colleague colleague) {
for (Colleague coll : colleagues) {
if (coll != colleague) {
coll.receive(message);
}
}
}
}
abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public abstract void send(String message);
public abstract void receive(String message);
}
class ConcreteColleague1 extends Colleague {
public ConcreteColleague1(Mediator mediator) {
super(mediator);
}
public void send(String message) {
System.out.println("Colleague1 sends message: " + message);
mediator.sendMessage(message, this);
}
public void receive(String message) {
System.out.println("Colleague1 received message: " + message);
}
}
class ConcreteColleague2 extends Colleague {
public ConcreteColleague2(Mediator mediator) {
super(mediator);
}
public void send(String message) {
System.out.println("Colleague2 sends message: " + message);
mediator.sendMessage(message, this);
}
public void receive(String message) {
System.out.println("Colleague2 received message: " + message);
}
}
public class Client {
public static void main(String[] args) {
Mediator mediator = new ConcreteMediator();
Colleague colleague1 = new ConcreteColleague1(mediator);
Colleague colleague2 = new ConcreteColleague2(mediator);
mediator.addColleague(colleague1);
mediator.addColleague(colleague2);
colleague1.send("Hi there!");
colleague2.send("Hello!");
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Colleague1 sends message: Hi there!
Colleague2 received message: Hi there!
Colleague2 sends message: Hello!
Colleague1 received message: Hello!
In this Java example, ConcreteMediator acts as the mediator handling communication between ConcreteColleague1 and ConcreteColleague2. This setup ensures that colleagues do not need direct references to each other to communicate, thus decoupling them and simplifying the interactions.
Memento Method Design Patterns
The Memento pattern is a behavioral design pattern that provides the ability to restore an object to its previous state (undo via rollback). This pattern is particularly useful in applications where the state of an object needs to be saved and restored later, such as in an undo mechanism in a text editor. It does this without exposing the internal details of the object.
When to use this
-
When you need to capture and restore an object's internal state without violating encapsulation.
-
When direct access to the object's fields/methods violates the encapsulation, but you still need to capture the object's state.
- When a snapshot of (some portion of) an object's state must be saved so that it can be restored to that state later.
Example
Java
import java.util.ArrayList;
import java.util.List;
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
class Originator {
private String state;
public void setState(String state) {
this.state = state;
System.out.println("State at Originator: " + state);
}
public Memento saveStateToMemento() {
return new Memento(state);
}
public void getStateFromMemento(Memento memento) {
state = memento.getState();
}
public String getState() {
return state;
}
}
class Caretaker {
private List<Memento> mementoList = new ArrayList<>();
public void add(Memento state) {
mementoList.add(state);
}
public Memento get(int index) {
return mementoList.get(index);
}
}
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State #1");
originator.setState("State #2");
caretaker.add(originator.saveStateToMemento());
originator.setState("State #3");
caretaker.add(originator.saveStateToMemento());
originator.setState("State #4");
originator.getStateFromMemento(caretaker.get(0));
System.out.println("First saved State: " + originator.getState());
originator.getStateFromMemento(caretaker.get(1));
System.out.println("Second saved State: " + originator.getState());
}
}

You can also try this code with Online Java Compiler
Run Code
Output
State at Originator: State #1
State at Originator: State #2
State at Originator: State #3
State at Originator: State #4
First saved State: State #2
Second saved State: State #3
In this Java example, the Originator class creates a Memento object to save its state. The Caretaker manages these memento objects, enabling the originator to return to its previous states. This design cleanly separates the details of object state storage from the object itself, ensuring that the object’s encapsulation remains intact.
Observer Method Design Pattern
The Observer pattern is a fundamental behavioral design pattern where an object, known as the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is particularly useful in scenarios where a change in one object requires one or more other objects to be updated automatically.
When to use this :
-
When changes to one object (the subject) need to be reflected in other objects (observers) without making the objects tightly coupled.
-
When the 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.
Example
Java
import java.util.ArrayList;
import java.util.List;
interface Observer {
void update();
}
interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
class ConcreteObserver implements Observer {
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject) {
this.subject = subject;
this.subject.attach(this);
}
public void update() {
System.out.println("State updated to: " + subject.getState());
}
}
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver(subject);
ConcreteObserver observer2 = new ConcreteObserver(subject);
subject.setState(10);
subject.setState(20);
}
}

You can also try this code with Online Java Compiler
Run Code
Output
State updated to: 10
State updated to: 10
State updated to: 20
State updated to: 20
In this Java example, ConcreteSubject maintains a list of observers that are interested in its state changes. Whenever the state of the ConcreteSubject changes (via setState), it notifies all registered observers by calling their update method. ConcreteObserver registers itself with the ConcreteSubject to receive updates.
State Method Design Pattern
The State pattern is a behavioral design pattern that allows an object to alter its behavior when its internal state changes. This pattern is seen as a clean way to express conditional branches in object-oriented programming that are dependent on the object's state. It encapsulates varying behaviors for the same routine based on the object's internal state, making state transitions explicit.
When to use this :
-
When an object's behavior changes depending on its state, and it must be able to change its behavior at runtime according to a new state.
-
When complex conditions tie object behavior to its state, and transitions between states need to be explicit and managed clearly.
- When you have large, monolithic conditional switches in multiple places that manipulate the object differently based on its internal state.
Example
Java
interface State {
void handle(Context context);
}
class Context {
private State currentState;
public Context(State state) {
this.currentState = state;
}
public void setState(State state) {
this.currentState = state;
}
public void request() {
currentState.handle(this);
}
}
class ConcreteStateA implements State {
public void handle(Context context) {
System.out.println("Handling request by ConcreteStateA");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB implements State {
public void handle(Context context) {
System.out.println("Handling request by ConcreteStateB");
context.setState(new ConcreteStateA());
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());
context.request(); // Output: Handling request by ConcreteStateA
context.request(); // Output: Handling request by ConcreteStateB
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Handling request by ConcreteStateA
Handling request by ConcreteStateB
In this Java example, the Context class holds a reference to a State object that represents its current state. By changing the state object within the Context, the behavior of the Context changes accordingly. This allows the Context to behave differently based on its internal state, which is changed dynamically during runtime by the state objects themselves.
Strategy Method Design Pattern
The Strategy pattern is a behavioral design pattern that enables selecting an algorithm's behavior at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use. It defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
When to use this :
-
When you want to define a family of algorithms or procedures that are interchangeable.
-
When you need to dynamically alter the behavior of an object.
- When you have a lot of conditional statements in the selection and execution of various algorithmic paths.
Example
Java
interface Strategy {
void executeStrategy();
}
class ConcreteStrategyA implements Strategy {
public void executeStrategy() {
System.out.println("Executing Strategy A");
}
}
class ConcreteStrategyB implements Strategy {
public void executeStrategy() {
System.out.println("Executing Strategy B");
}
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void executeStrategy() {
strategy.executeStrategy();
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context(new ConcreteStrategyA());
context.executeStrategy(); // Output: Executing Strategy A
context.setStrategy(new ConcreteStrategyB());
context.executeStrategy(); // Output: Executing Strategy B
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Executing Strategy A
Executing Strategy B
In this Java example, Context uses a Strategy interface to define a family of algorithms. The ConcreteStrategyA and ConcreteStrategyB classes implement this interface with different behaviors. The Context can change its executing strategy dynamically, allowing the behavior change at runtime depending on the strategy set.
Template Method Design Pattern
The Template Method pattern is a behavioral design pattern that defines the program skeleton of an algorithm in a method, deferring some steps to subclasses. This pattern lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. It is particularly useful when there is a prescribed order of steps to perform a task, but the specifics of those steps might vary between different implementations.
When to use this :
-
When you want to let clients extend only particular steps of an algorithm without changing the algorithm's structure.
-
When the common behavior among subclasses should be factored and centralized in a common class to avoid code duplication.
- When you need to control the point at which specialization is implemented by subclasses.
Example
Java
abstract class AbstractClass {
// Template method defines the skeleton of an algorithm.
public final void templateMethod() {
stepOne();
stepTwo();
stepThree();
}
protected abstract void stepOne();
protected abstract void stepTwo();
protected abstract void stepThree();
}
class ConcreteClass extends AbstractClass {
protected void stepOne() {
System.out.println("Step One implemented by ConcreteClass");
}
protected void stepTwo() {
System.out.println("Step Two implemented by ConcreteClass");
}
protected void stepThree() {
System.out.println("Step Three implemented by ConcreteClass");
}
}
public class Client {
public static void main(String[] args) {
AbstractClass obj = new ConcreteClass();
obj.templateMethod(); // Executes steps one, two, and three in order.
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Step One implemented by ConcreteClass
Step Two implemented by ConcreteClass
Step Three implemented by ConcreteClass
In this Java example, the AbstractClass defines a templateMethod() that outlines the steps of the algorithm. Each step (stepOne(), stepTwo(), stepThree()) is implemented by the ConcreteClass. This setup ensures that the overarching procedure is followed, while allowing flexibility in the implementation of each step.
Visitor Method Design Pattern
The Visitor pattern is a behavioral design pattern that allows you to separate algorithms from the objects on which they operate. This pattern provides a way to add new operations to existing object structures without modifying those structures. It is particularly useful when you need to perform various unrelated operations across a class hierarchy but don't want to clutter the classes with these operations.
When to use this :
-
When an object structure includes many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes.
-
When new operations need to be added to complex class hierarchies without changing the classes on which they operate.
- When a class hierarchy is unlikely to change but you need to be able to change the operations performed upon it.
Example
Java
interface Visitor {
void visitConcreteElementA(ConcreteElementA element);
void visitConcreteElementB(ConcreteElementB element);
}
class ConcreteVisitor implements Visitor {
public void visitConcreteElementA(ConcreteElementA element) {
System.out.println("Visiting ConcreteElementA");
}
public void visitConcreteElementB(ConcreteElementB element) {
System.out.println("Visiting ConcreteElementB");
}
}
interface Element {
void accept(Visitor visitor);
}
class ConcreteElementA implements Element {
public void accept(Visitor visitor) {
visitor.visitConcreteElementA(this);
}
}
class ConcreteElementB implements Element {
public void accept(Visitor visitor) {
visitor.visitConcreteElementB(this);
}
}
public class Client {
public static void main(String[] args) {
Element[] elements = {new ConcreteElementA(), new ConcreteElementB()};
Visitor visitor = new ConcreteVisitor();
for (Element element : elements) {
element.accept(visitor);
}
}
}

You can also try this code with Online Java Compiler
Run Code
Output
Visiting ConcreteElementA
Visiting ConcreteElementB
In this Java example, Element interface declares an accept method that takes a Visitor object as an argument. ConcreteElementA and ConcreteElementB implement the Element interface and define how to accept a visitor. ConcreteVisitor implements the Visitor interface and knows how to process different types of elements. This separation of concerns allows adding new operations to existing object structures without modifying them.
Frequently Asked Questions
What is the main advantage of using behavioral design patterns?
Behavioral patterns primarily simplify the communication between objects in large applications, making interactions more manageable and extensible.
Can behavioral design patterns be combined in a software project?
Yes, multiple behavioral design patterns can be used in conjunction to solve complex design problems and enhance flexibility in the code.
How do behavioral design patterns affect the maintenance of code?
They promote better organization and decoupling of responsibilities, which significantly eases the process of code maintenance and modification.
Conclusion
In this article, we have learned about various behavioral design patterns, which are instrumental in managing complex communications within software applications. From the Chain of Responsibility facilitating request handling among a sequence of handlers to the Visitor pattern allowing operations to be performed on elements without changing their classes, these patterns offer elegant solutions to common problems faced in object-oriented design. Each pattern provides a framework that not only enhances the modularity and reusability of code but also helps maintain a clear separation of concerns, making software easier to develop, maintain, and scale.
You can refer to our guided paths on the Coding Ninjas. You can check our course to learn more about DSA, DBMS, Competitive Programming, Python, Java, JavaScript, etc. Also, check out some of the Guided Paths on topics such as Data Structure andAlgorithms, Competitive Programming, Operating Systems, Computer Networks, DBMS, System Design, etc., as well as some Contests, Test Series, and Interview Experiences curated by top Industry.