SDSU CS 696: Advanced OO
Spring Semester, 1997
Doc 17, Chain of Responsibility, Interpreter

To Lecture Notes Index
San Diego State University -- This page last updated Apr 22, 1997

Contents of Doc 17, Chain of Responsibility, Interpreter


Chain of Responsibility slide # 1
...Intent slide # 1
...When to Use slide # 1
...Participants slide # 3
...Implementation Issues slide # 4
Interpreter slide # 7
...Consequences slide # 10
...Implementation slide # 10


Doc 17, Chain of Responsibility, Interpreter Slide # 1

Chain of Responsibility

Intent


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.

When to Use


When more than on object may handle a request, and the handler isn't known a priori

When you want to issue a request to one of several objects without specifying the receiver explicitly

When the set of objects that can handle a request should be specified dynamically



Doc 17, Chain of Responsibility, Interpreter Slide # 2
How does this differ from Decorator?






Doc 17, Chain of Responsibility, Interpreter Slide # 3

Participants

handler
Defines the interface for handling the requests

May implement the successor link

ConcreteHandler
Handles requests it is responsible for

Can access its successor

Handles the request if it can do so, otherwise it forwards the request to its successor

Consequences
Reduced coupling

Added flexibility in assigning responsibilities to objects

Not guaranteed that request will be handled


Doc 17, Chain of Responsibility, Interpreter Slide # 4

Implementation Issues

The successor chain

The concrete handlers may already have pointers to their successors, so just use them

Give each handler a link to its successor

Representing Requests

abstract class HardCodedHandler
     {
     private HardCodedHandler successor;
     
     public HardCodedHandler( HardCodedHandler aSuccessor)
          { successor = aSuccessor; }
     
     public void handleOpen()
          { successor.handleOpen(); }
     
     public void handleClose()
          { successor.handleClose(); }

     public void handleNew( String fileName)
          { successor.handleClose( fileName ); }
     }


Doc 17, Chain of Responsibility, Interpreter Slide # 5
€ A single method implements all requests
abstract class SingleHandler
     {
     private SingleHandler successor;
     
     public SingleHandler( SingleHandler aSuccessor)
          {
          successor = aSuccessor;
          }
     
     public void handle( String request)
          {
          successor.handle( request );
          }
     }

class ConcreteOpenHandler extends SingleHandler
     {
     public void handle( String request)
          {
          switch ( request )
               {
               case "Open" : do the right thing;
               case "Close" : more right things;
               case "New" : even more right things;
               default: successor.handle( request );
               }
          }

}


Doc 17, Chain of Responsibility, Interpreter Slide # 6
€ Single handle method with Request Object for parameters

abstract class SingleHandler
     {
     private SingleHandler successor;
     
     public SingleHandler( SingleHandler aSuccessor)
          {successor = aSuccessor; }
     
     public void handle( Request data)
          { successor.handle( data ); }
     }

class ConcreteOpenHandler extends SingleHandler
     {
     public void handle( Open data)
          { // handle the open here }
     }
     
class Request
     {
     private int size;
     private String name;
     public Request( int mySize, String myName)
          { size = mySize;  name = myName; }
     
     public int size() { return size; }
     public String name() { return name;}
     }

class Open extends Request
     {// add Open specific stuff here}
     
class Close extends Request
     { // add Close specific stuff here}


Doc 17, Chain of Responsibility, Interpreter Slide # 7

Interpreter


Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language

Example - Arithmetic Expressions

interface ArithmeticExpression
     {
     public Number evaluate( Context data);
     }

class BinaryOperator implements ArithmeticExpression
     {
     private ArithmeticExpression leftOperand;
     private ArithmeticExpression rightOperand;
     private String operator;
     
     public BinaryOperator( String anOperator)
          { operator = anOperator;}
          
     public void setLeftOperand(ArithmeticExpression anExpression)
          {
          leftOperand = anExpression;
          }

     public void setRightOperand(ArithmeticExpression anExpression)
          {
          rightOperand = anExpression;
          }


Doc 17, Chain of Responsibility, Interpreter Slide # 8

public Number evaluate( Context environment)
          {     
          Number right = rightOperand.evaluate( environment );
          Number left = leftOperand.evaluate( environment );
          
          switch ( operator )
               {
               case "*": return right * left );
               case "+": return right + left );
               etc.
               }
          }
     }
     
class Constant implements ArithmeticExpression
     {
     private Number value;

     public Constant( Number aValue)
          { value = aValue;}
     
     public Number evaluate( Context environment) 
          { return value; }
     }
     
class Variable implements ArithmeticExpression
     {
     private String name;
     
     public Variable( String aName )
          { name = aName; }
     
     public Number evaluate( Context environment)
Doc 17, Chain of Responsibility, Interpreter Slide # 9
{ return environment.getValueOf( name );} }

class Context
     {
     private Hashtable variables = new Hashtable();
     
     public void setValueOf( String name, Object value)
          {
          variables.put( name, value);
          }

     public void getValueOf( String name)
          {
          return variables.get( name);
          }
     }     



Doc 17, Chain of Responsibility, Interpreter Slide # 10

Consequences


It's easy to change and extend the grammar

Implementing the grammar is easy

Complex grammars are hard to maintain

Adding new ways to interpret expressions

The visiter pattern is useful here

Implementation


The pattern does not talk about parsing!