blogger templates blogger widgets
This is part of a list of blog posts.
To browse the contents go to

Behavioural Design Patterns


Template Method pattern

It defines the steps to execute an algorithm in the base class and it can provide default implementation that might be common for all or some of the subclasses.

Client:

Tea tea = new Tea();
tea.prepareRecipe();
Coffee coffee = new Coffee();
coffee.prepareRecipe();



// We find that the algorithm to make coffee and tea are similar and they are
// not supposed to be controlled within the Tea or Coffee classes instead 
// the algorithm should be moved out

abstract class Beverage {
final public void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}

abstract public void brew();

abstract public void addCondiments();

//some of the methods could be final - making that step in the algorithm compulsory
public final void boilWater() {
println("Boil water");
}

public void pourInCup() {
println("Pour in Cup");
}
}

class Coffee extends Beverage {
public void brew() {
println("Brew Coffee");
}

public void addCondiments() {
println("Add Sugar and Milk");
}
}

class Tea extends Beverage {
public void brew() {
println("Steep Tea");
}

public void addCondiments() {
println("Add Lemon");
}
}

JDK:
All non-abstract methods of InputStream, OutputStream, Reader, Writer
All non-abstract methods of AbstractList, AbstractSet and AbstractMap



Mediator pattern

Mediator design pattern is used to provide a centralized communication medium between different objects in a system.

Client:

ChatMediator mediator = new ChatMediator();
User user1 = new Personal(mediator, "John");
User user2 = new Personal(mediator, "Kamal");
User user3 = new Manager(mediator, "Geo");

user2.send("hello people");
user3.send("hello boys");


/*
* 
* Mediator design pattern is used to provide a centralized communication medium
* between different objects in a system.
*/
abstract class User {
protected ChatMediator mediator;
protected String name;

public User(ChatMediator med, String name) {
this.mediator = med;
this.name = name;
this.mediator.addUser(this);
}

public abstract void send(String msg);

public abstract void receive(String msg);
}

class Personal extends User {

public Personal(ChatMediator med, String name) {
super(med, name);
}

@Override
public void send(String msg) {
println(this.name+": Sending Message="+msg); 
mediator.sendMessage(msg, this);
}

@Override
public void receive(String msg) {
println(this.name+": Received Message:"+msg);
}

}


class Manager extends User {

public Manager(ChatMediator med, String name) {
super(med, name);
}

@Override
public void send(String msg) {
println(this.name+": Sending Sacred Message="+msg); 
mediator.sendMessage(msg, this);
}

@Override
public void receive(String msg) {
println(this.name+": Received Message:"+msg);
}

}

//Mediator class helps to provide a mechanism for different user objects to
//communicate

class ChatMediator  {
private List users;

public ChatMediator() {
this.users = new ArrayList<>();
}

public void addUser(User user) {
this.users.add(user);
}

public void sendMessage(String msg, User user) {
for (User u : this.users) {
// message should not be received by the user sending it
if (u != user) {
u.receive(msg);
}
}
}
}

Output:
[main] Kamal: Sending Message=hello people
[main] John: Received Message:hello people
[main] Geo: Received Message:hello people
[main] Geo: Sending Sacred Message=hello boys
[main] John: Received Message:hello boys
[main] Kamal: Received Message:hello boys

JDK:
java.util.Timer class scheduleXXX() methods
Java Concurrency Executor execute() method
java.lang.reflect.Method invoke() method
JMS



Chain of responsibility pattern

It is used to achieve lose coupling in software design where a request from client is passed to a chain of objects to process them. Then the object in the chain will decide themselves who will be processing the request and whether the request is required to be sent to the next object in the chain or not.

Client:

DispenseChain chain5 = new Dollar50Dispenser();
DispenseChain chain2 = new Dollar20Dispenser();
DispenseChain chain1 = new Dollar10Dispenser();
chain5.setNextChain(chain2);
chain2.setNextChain(chain1);

chain5.dispense(new Currency(187));



/**
* Gives more than one object an opportunity to handle a request by linking
* receiving objects together.
*/

// this is the object that is handled
class Currency {
private int amount;

public Currency(int amt) {
amount = amt;
}

public int getAmount() {
return amount;
}
}

// this is the interface for all request handlers
interface DispenseChain {
void setNextChain(DispenseChain nextChain);

void dispense(Currency cur);
}

class Dollar50Dispenser implements DispenseChain {
private DispenseChain chain;

@Override
public void setNextChain(DispenseChain nextChain) {
chain = nextChain;
}

@Override
public void dispense(Currency cur) {
if (cur.getAmount() >= 50) {
int num = cur.getAmount() / 50;
int remainder = cur.getAmount() % 50;
println("Dispensing " + num + " 50$ note");
if (remainder != 0)
chain.dispense(new Currency(remainder));
} else {
chain.dispense(cur);
}
}
}

class Dollar20Dispenser implements DispenseChain {
private DispenseChain chain;

@Override
public void setNextChain(DispenseChain nextChain) {
chain = nextChain;
}

@Override
public void dispense(Currency cur) {
if (cur.getAmount() >= 20) {
int num = cur.getAmount() / 20;
int remainder = cur.getAmount() % 20;
println("Dispensing " + num + " 20$ note");
if (remainder != 0)
chain.dispense(new Currency(remainder));
} else {
chain.dispense(cur);
}
}
}

class Dollar10Dispenser implements DispenseChain {
 private DispenseChain chain;

 @Override
 public void setNextChain(DispenseChain nextChain) {
  chain = nextChain;
 }

 @Override
 public void dispense(Currency cur) {
  int num = cur.getAmount() / 10;
  int remainder = cur.getAmount() % 10;
  println("Dispensing " + num + " 10$ note");
  if (remainder != 0) {
   if (chain != null && remainder > 10) {
    chain.dispense(new Currency(remainder));
   } else {
    println("Unable to dispence " + remainder + " ,amound should be in the multiples of 10");
   }
  }

 }
}

Output:
[main] Dispensing 3 50$ note
[main] Dispensing 1 20$ note
[main] Dispensing 1 10$ note
[main] Unable to dispence 7 ,amound should be in the multiples of 10

JDK:
java.util.logging.Logger#log()
javax.servlet.Filter#doFilter()



Observer Pattern

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

A very common example is Publish/Subscriber on Topics.

Client:

MyTopic topic = new MyTopic();

// create observers
Observer obj1 = new MyTopicSubscriber("observer-1");
Observer obj2 = new MyTopicSubscriber("observer-2");
Observer obj3 = new MyTopicSubscriber("observer-3");

// register observers to the subject
topic.register(obj1);
topic.register(obj2);
topic.register(obj3);

// attach observer to subject
obj1.setSubject(topic);
obj2.setSubject(topic);
obj3.setSubject(topic);

// check if any update is available
obj1.update();

// now send message to subject
topic.postMessage("New Message");



interface Subject {
// methods to register and unregister observers
public void register(Observer obj);

public void unregister(Observer obj);

// method to notify observers of change
public void notifyObservers();

// method to get updates from subject
public Object getUpdate(Observer obj);
}

interface Observer {
// method to update the observer, used by subject
public void update();

// attach with subject to observe
public void setSubject(Subject sub);
}

class MyTopic implements Subject {

private List<observer> observers;
private String message;
private boolean changed;
private final Object MUTEX = new Object();

public MyTopic() {
observers = new ArrayList<>();
}

@Override
public void register(Observer obj) {
if (obj == null)
throw new NullPointerException("Null Observer");
synchronized (MUTEX) {
if (!observers.contains(obj))
observers.add(obj);
}
}

@Override
public void unregister(Observer obj) {
synchronized (MUTEX) {
observers.remove(obj);
}
}

@Override
public void notifyObservers() {
List observersLocal = null;
// synchronization is used to make sure any observer registered
// after message is received is not notified
synchronized (MUTEX) {
if (!changed)
return;
observersLocal = new ArrayList<>(observers);
changed = false;
}
for (Observer obj : observersLocal) {
obj.update();
}
}

@Override
public Object getUpdate(Observer obj) {
return message;
}

// method to post message to the topic
public void postMessage(String msg) {
println("Message Posted to Topic:" + msg);
message = msg;
changed = true;
notifyObservers();
}
}

class MyTopicSubscriber implements Observer {

private String name;
private Subject topic;

public MyTopicSubscriber(String nm) {
name = nm;
}

@Override
public void update() {
String msg = (String) topic.getUpdate(this);
if (msg == null) {
println(name + ":: No new message");
} else
println(name + ":: Consuming message::" + msg);
}

@Override
public void setSubject(Subject sub) {
topic = sub;
}
}

Output:
[main] observer-1:: No new message
[main] Message Posted to Topic:New Message
[main] observer-1:: Consuming message::New Message
[main] observer-2:: Consuming message::New Message
[main] observer-3:: Consuming message::New Message



Strategy pattern

It is used when we have multiple algorithm for a specific task and client decides the actual implementation to be used at runtime.

Strategy pattern is also known as Policy Pattern.

Client:

Customer a = new Customer(new NormalStrategy());

// Normal billing
a.add(1.0, 1);

// Start Happy Hour
a.setStrategy(new HappyHourStrategy());
a.add(1.0, 2);

a.printBill();


class Customer {

private List drinks;

//if strategy pattern was not used then
//we would have getPrice method in Customer class and 
//will have a huge if else statement for different customer strategy 
//scenarios. the pattern helps to take that logic out and
//make it extensible and modifiable without touching the customer class

private BillingStrategy strategy;

public Customer(BillingStrategy strategy) {
drinks = new ArrayList();
this.strategy = strategy;
}

public void add(double price, int quantity) {
drinks.add(strategy.getFinalPrice(price * quantity));
}

// Payment of bill
public void printBill() {
double sum = 0;
for (Double i : drinks) {
sum += i;
}
System.out.println("Total due: " + sum);
drinks.clear();
}

// Set Strategy
public void setStrategy(BillingStrategy strategy) {
this.strategy = strategy;
}

}


interface BillingStrategy {
public double getFinalPrice(double rawPrice);
}

// Normal billing strategy (unchanged price)
class NormalStrategy implements BillingStrategy {

@Override
public double getFinalPrice(double rawPrice) {
return rawPrice;
}

}

// Strategy for Happy hour (50% discount)
class HappyHourStrategy implements BillingStrategy {

@Override
public double getFinalPrice(double rawPrice) {
return rawPrice * 0.5;
}

}

JDK:
Collections.sort()
Arrays.sort()



Command pattern

It’s used to implement lose coupling in a request-response model. In command pattern, the request is send to the invoker and invoker pass it to the encapsulated command object. Command object passes the request to the appropriate method of Receiver to perform the specific action.

Client:

Computer computer = new Computer();
Command shutdown = new ShutDownCommand(computer);
Command restart = new RestartCommand(computer);

Switch s = new Switch();

String str = "shutdown"; // get value based on real situation

if (str == "shutdown") {
s.storeAndExecute(shutdown);
} else {
s.storeAndExecute(restart);
}


/* The Command interface */
interface Command {
void execute();
}

// in this example, suppose you use a switch to control computer

/* The Invoker class */
class Switch {
private List history = new ArrayList();

public Switch() {
}

public void storeAndExecute(Command command) {
history.add(command); // optional, can do the execute only!
command.execute();
}
}

/* The Receiver class */
class Computer {

public void shutDown() {
println("computer is shut down");
}

public void restart() {
println("computer is restarted");
}
}

/* The Command for shutting down the computer */
class ShutDownCommand implements Command {
private Computer computer;

public ShutDownCommand(Computer computer) {
this.computer = computer;
}

public void execute() {
computer.shutDown();
}
}

/* The Command for restarting the computer */
class RestartCommand implements Command {
private Computer computer;

public RestartCommand(Computer computer) {
this.computer = computer;
}

public void execute() {
computer.restart();
}
}

JDK:
Runnable
swing.Action



State pattern

If we have to change the behavior of an object based on its state, we can have a state variable in the Object and use if-else condition block to perform different actions based on the state. State pattern is used to provide a systematic and lose-coupled way to achieve this through Context and State implementations.
Context is the class that has a State reference to one of the concrete implementations of the State and forwards the request to the state object for processing.

Client:

MusicContext musicCtx = new MusicContext(new HashMap<String, List<String>>() {
{
put("bliss", new ArrayList<String>() {
{
add("Let it be");
add("Happy happy");
}
});
put("depress", new ArrayList<String>() {
{
add("Knife on");
add("Bad day");
}
});
}
});

musicCtx.setState(new BlissfulState());
musicCtx.doPlay();

Context and state classes:


interface MusicState {

public void doPlay(MusicContext ctx);
}

class BlissfulState implements MusicState {
public void doPlay(MusicContext ctx) {
println(ctx.getMusicDB().get("bliss").get(ThreadLocalRandom.current().nextInt(0, 2)));
}
}

class DepressedState implements MusicState {
public void doPlay(MusicContext ctx) {
println(ctx.getMusicDB().get("depress").get(ThreadLocalRandom.current().nextInt(0, 2)));
}
}

class MusicContext {

MusicState myState;

private Map<String, List<String>> musicDB;

MusicContext(Map<String, List<String>> musicDB) {
this.setMusicDB(musicDB);
if (myState == null)
setState(new BlissfulState());
}

public void setState(final MusicState newState) {
myState = newState;
}

public void doPlay() {
myState.doPlay(this);
}

public Map<String, List<String>> getMusicDB() {
return musicDB;
}

public void setMusicDB(Map<String, List<String>> musicDB) {
this.musicDB = musicDB;
}
}

Another approach:

/**
* in the above case the states themselves aren't directly related the control
* to change the state is given to the external program
* 
* but if the state is to be maintained internally then we use an abstract class
* instead of interface and create final state objects.
* 
* the abstract class then will have a protected constructor.
**/

abstract class State {
static State initialState;
static final State state1 = new State1();
static final State state2 = new State2();

protected State() {
if (initialState == null)
initialState = this;
}

abstract void stateExit(StateContext owner);

abstract void stateEnter(StateContext owner);
}

class State1 extends State {
void stateExit(StateContext owner) {
}

void stateEnter(StateContext owner) {
}
}

class State2 extends State {
void stateExit(StateContext owner) {
}

void stateEnter(StateContext owner) {
}
}

class StateContext {

private State stateVar;

// Create the object and initialize its state
public StateContext() {
this.stateVar = State.state1;
stateVar.stateEnter(this);
}

// Set the new state
public void setState(State newState) {
stateVar.stateExit(this);
this.stateVar = newState;
stateVar.stateEnter(this);
}
}


Visitor pattern

is used when we have to perform an operation on a group of similar kind of Objects. With the help of visitor pattern, we can move the operational logic from the objects to another class.
For example, think of a Shopping cart where we can add different type of items (Elements), when we click on checkout button, it calculates the total amount to be paid.

Client:

ItemElement[] cart = new ItemElement[] { new Book(20, "1234"), 
new Book(100, "5678"), 
new Eatables(10, 2), 
new Eatables(5, 5) };
int total = calculatePrice(cart);
println("Total Cost = " + total);

private static int calculatePrice(ItemElement[] items) {
ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
int sum = 0;
for (ItemElement item : items) {
sum = sum + item.accept(visitor);
}
return sum;
}



interface ItemElement {
public int accept(ShoppingCartVisitor visitor);
}

class Book implements ItemElement {
private int price;
private String isbnNumber;

public Book(int cost, String isbn) {
this.price = cost;
this.isbnNumber = isbn;
}

public int getPrice() {
return price;
}

public String getIsbnNumber() {
return isbnNumber;
}

@Override
public int accept(ShoppingCartVisitor visitor) {
return visitor.visit(this);
}
}

class Eatables implements ItemElement {
private int pricePerKg;
private int weight;

public Eatables(int priceKg, int wt) {
this.pricePerKg = priceKg;
this.weight = wt;
}

public int getPricePerKg() {
return pricePerKg;
}

public int getWeight() {
return weight;
}

@Override
public int accept(ShoppingCartVisitor visitor) {
return visitor.visit(this);
}
}

interface ShoppingCartVisitor {
int visit(Book book);
int visit(Eatables fruit);
}

class ShoppingCartVisitorImpl implements ShoppingCartVisitor {
@Override
public int visit(Book book) {
int cost = 0;
// apply 5$ discount if book price is greater than 50
if (book.getPrice() > 50) {
cost = book.getPrice() - 5;
} else
cost = book.getPrice();
println("Book ISBN::" + book.getIsbnNumber() + " cost =" + cost);
return cost;
}

@Override
public int visit(Eatables fruit) {
int cost = fruit.getPricePerKg() * fruit.getWeight();
println(" cost = " + cost);
return cost;
}
}

Another interesting example: JavaWorld-Java-Tip-98-Article

Interpreter pattern

is used to define a grammatical representation for a language and provides an interpreter to deal with this grammar.

Client:


String expression = "w x z - +";
Evaluator sentence = new Evaluator(expression);
Map<String,Expression> variables = new HashMap<String,Expression>();
variables.put("w", new Number(5));
variables.put("x", new Number(10));
variables.put("z", new Number(42));
int result = sentence.interpret(variables);
System.out.println(result);


interface Expression {
public int interpret(Map<String,Expression> variables);
}

class Number implements Expression {
private int number;
public Number(int number)       { this.number = number; }
public int interpret(Map<String,Expression> variables)  { return number; }
}

class Plus implements Expression {
Expression leftOperand;
Expression rightOperand;
public Plus(Expression left, Expression right) { 
leftOperand = left; 
rightOperand = right;
}

public int interpret(Map<String,Expression> variables)  { 
return leftOperand.interpret(variables) + rightOperand.interpret(variables);
}
}

class Minus implements Expression {
Expression leftOperand;
Expression rightOperand;
public Minus(Expression left, Expression right) { 
leftOperand = left; 
rightOperand = right;
}

public int interpret(Map<String,Expression> variables)  { 
return leftOperand.interpret(variables) - rightOperand.interpret(variables);
}
}

class Variable implements Expression {
private String name;
public Variable(String name)       { this.name = name; }
public int interpret(Map<String,Expression> variables)  { 
if(null==variables.get(name)) return 0; //Either return new Number(0).
return variables.get(name).interpret(variables); 
}
}

class Evaluator implements Expression {
private Expression syntaxTree;

public Evaluator(String expression) {
Stack<Expression> expressionStack = new Stack<Expression>();
for (String token : expression.split(" ")) {
if  (token.equals("+")) {
Expression subExpression = new Plus(expressionStack.pop(), expressionStack.pop());
expressionStack.push( subExpression );
}
else if (token.equals("-")) {
// it's necessary remove first the right operand from the stack
Expression right = expressionStack.pop();
// ..and after the left one
Expression left = expressionStack.pop();
Expression subExpression = new Minus(left, right);
expressionStack.push( subExpression );
}
else                        
expressionStack.push( new Variable(token) );
}
syntaxTree = expressionStack.pop();
}

public int interpret(Map<String,Expression> context) {
return syntaxTree.interpret(context);
}
}

JDK:
java.util.Pattern and
subclasses of java.text.Format



Iterator pattern

Provides a way to access the elements of an aggregate object without exposing its underlying representation.

List<Integer> list = new ArrayList<Integer>();
list.add(2);list.add(40);

Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}

No comments:

Post a Comment