tl  tr
  Home | Tutorials | Articles | Videos | Products | Tools | Search
Interviews | Open Source | Tag Cloud | Follow Us | Bookmark | Contact   
 Design Patterns > Java Design Patterns > Chain Of Responsibility

Chain Of Responsibility 

Chain of responsibility pattern comes under Behavioral design pattern. It lets more than one receiver handler to process the request and decouples the sender of request to its receiver.

Behaviour & Advantages

  • Chains the receiving objects and passes request through chain until its handled by a receiver.
  • The receiver is determined based on request data.
  • The receiver takes the responsibility of delegating to next receiver in chain if it cannot process the request.
  • Decouples the sender of request to its receiver.

This example shows a Travel suggest where user inputs the distance to travel. Travel suggest outputs best travel means for the distance given. Interface ITravelHandler acts as Handler and classes Walk, Bus, Train, Airplane & Rocket acts as ConcreteHandlers or Receivers which can be chained together by TravelSuggest class.

Travel data is shown below,

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/TravelData.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility;

public class TravelData {
  /**
   * Distance to travel in KMs
   */
  private int distance;

  public TravelData(int distance) {
    super();
    this.distance = distance;
  }

  public int getDistance() {
    return distance;
  }

  public void setDistance(int distance) {
    this.distance = distance;
  }
}
   

The travel handler is shown below,

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/ITravelHandler.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility;

public interface ITravelHandler {
  
  /**
   * Process the travel data
   */
  public void processHandler(TravelData travelData);
  
  /**
   * Set next handler in the chain
   */
  public void setNextHandler(ITravelHandler travelHandler);

  /**
   * Get next handler in the chain
   */
  public ITravelHandler getNextHandler();

}
   

We can see that there is min and mix limit on distance to be processed by each receiver handler. If the current handler cannot process the travel data, it will delegate the request processing to next handler in the chain. The abstract and concrete implementations of handlers are shown below,

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/chain/AbstractTravelHandler.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility.chain;

import com.bethecoder.tutorials.dp.chain_of_responsibility.ITravelHandler;
import com.bethecoder.tutorials.dp.chain_of_responsibility.TravelData;

public abstract class AbstractTravelHandler implements ITravelHandler {

  /**
   * Min/Max distance we can travel.
   @return
   */
  public abstract int getMinDistance();
  public abstract int getMaxDistance();
  
  /**
   * Next handler in the chain.
   */
  private ITravelHandler nextHandler;
  
  
  @Override
  public void processHandler(TravelData travelData) {
    if (travelData.getDistance() >= getMinDistance() && 
        travelData.getDistance() < getMaxDistance()) {
      
      System.out.println("Best choice for distance (" 
          travelData.getDistance() "KM) is '" this.getClass().getSimpleName() "'");
      
    else if (getNextHandler() != null) {
      getNextHandler().processHandler(travelData);
    else {
      System.out.println("Couldn't process travel data.");
    }
  }

  @Override
  public void setNextHandler(ITravelHandler travelHandler) {
    if (this.nextHandler == null) {
      this.nextHandler = travelHandler;
    else {
      this.nextHandler.setNextHandler(travelHandler);
    }
  }

  public ITravelHandler getNextHandler() {
    return nextHandler;
  }

  public String toString() {
    return this.getClass().getSimpleName() 
        "[" + getMinDistance() "-" + getMaxDistance() "]";
  }
}
   

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/chain/Walk.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility.chain;

public class Walk extends AbstractTravelHandler {

  @Override
  public int getMinDistance() {
    return 0;
  }
  
  @Override
  public int getMaxDistance() {
    return 5;
  }
}
   

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/chain/Bus.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility.chain;

public class Bus extends AbstractTravelHandler {

  @Override
  public int getMinDistance() {
    return 5;
  }
  
  @Override
  public int getMaxDistance() {
    return 20;
  }
}
   

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/chain/Train.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility.chain;

public class Train extends AbstractTravelHandler {

  @Override
  public int getMinDistance() {
    return 20;
  }
  
  @Override
  public int getMaxDistance() {
    return 100;
  }
}
   

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/chain/Airplane.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility.chain;

public class Airplane extends AbstractTravelHandler {

  @Override
  public int getMinDistance() {
    return 100;
  }
  
  @Override
  public int getMaxDistance() {
    return 1000;
  }
}
   

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/chain/Rocket.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility.chain;

public class Rocket extends AbstractTravelHandler {

  @Override
  public int getMinDistance() {
    return 1000;
  }
  
  @Override
  public int getMaxDistance() {
    return Integer.MAX_VALUE;
  }
}
   

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/TravelSuggest.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility;

public class TravelSuggest {

  private ITravelHandler travelHandler;
  
  public void addTravelHandler(ITravelHandler travelHandler) {
    if (this.travelHandler == null) {
      this.travelHandler = travelHandler; 
    else {
      this.travelHandler.setNextHandler(travelHandler);
    }
  }
  
  public void suggest(TravelData travelData) {
    travelHandler.processHandler(travelData);
  }
  
  public void introspect() {
    ITravelHandler curTravelHandler = travelHandler;
    System.out.print("INTROSPECT : ");
    
    while (curTravelHandler != null) {
      System.out.print(curTravelHandler);
      
      if (curTravelHandler.getNextHandler() != null) {
        System.out.print(" < ");
      }
      
      curTravelHandler = curTravelHandler.getNextHandler();
    }
    
    System.out.println();
  }
}
   

Travel suggest usage is shown below,

File Name  :  
com/bethecoder/tutorials/dp/chain_of_responsibility/Test.java 
   
package com.bethecoder.tutorials.dp.chain_of_responsibility;

import com.bethecoder.tutorials.dp.chain_of_responsibility.chain.Airplane;
import com.bethecoder.tutorials.dp.chain_of_responsibility.chain.Bus;
import com.bethecoder.tutorials.dp.chain_of_responsibility.chain.Rocket;
import com.bethecoder.tutorials.dp.chain_of_responsibility.chain.Train;
import com.bethecoder.tutorials.dp.chain_of_responsibility.chain.Walk;

public class Test {

  /**
   @param args
   */
  public static void main(String[] args) {

    TravelSuggest travelSuggest = new TravelSuggest();
    travelSuggest.addTravelHandler(new Walk());
    travelSuggest.addTravelHandler(new Bus());
    travelSuggest.addTravelHandler(new Train());
    travelSuggest.addTravelHandler(new Airplane());
    travelSuggest.addTravelHandler(new Rocket());
    travelSuggest.introspect();
    
    System.out.println();
    
    TravelData travelData = new TravelData(4);
    travelSuggest.suggest(travelData);
    
    travelData = new TravelData(12);
    travelSuggest.suggest(travelData);
    
    travelData = new TravelData(56);
    travelSuggest.suggest(travelData);
    
    travelData = new TravelData(968);
    travelSuggest.suggest(travelData);
    
    travelData = new TravelData(6789);
    travelSuggest.suggest(travelData);
    
    travelData = new TravelData(-1);
    travelSuggest.suggest(travelData);
    
  }
}
   

It gives the following output,
INTROSPECT : Walk[0-5] < Bus[5-20] < 
		Train[20-100] < Airplane[100-1000] < Rocket[1000-2147483647]

Best choice for distance (4KM) is 'Walk'
Best choice for distance (12KM) is 'Bus'
Best choice for distance (56KM) is 'Train'
Best choice for distance (968KM) is 'Airplane'
Best choice for distance (6789KM) is 'Rocket'
Couldn't process travel data.



 
  


  
bl  br