Recipe19.5.Implementing the Chain of Responsibility Pattern


Recipe 19.5. Implementing the Chain of Responsibility Pattern

Problem

You want to apply the chain of responsibility pattern using AspectJ.

Solution

The chain of responsibility pattern allows the separation of the source of a request from deciding which of the potentially large number of handlers for the request should action it. The class representing the chain role channels the requests from the source along the list of handlers until a handler accepts the request and actions it.

The abstract aspect in Example 19-9 uses the Director aspect-oriented design pattern (see Chapter 23) to provide the generic mechanisms by which the chain of responsibility pattern can be applied to an application. The decision as to what occurs if none of the available handlers in the chain accept the request is an application-specific decision; although a default behavior is implemented in the abstract aspect, this can be overridden by extending implementations.

Example 19-9. Defining the chain of responsibility pattern using aspects
public abstract aspect ChainOfResponsibilityPattern  {    protected interface Handler    {    }    public WeakHashMap successors = new WeakHashMap( );    protected void receiveRequest(Handler handler, Object request)    {       if (handler.acceptRequest(request))       {          handler.handleRequest(request);       }        else       {          // The handler will not accept the request          Handler successor = getSuccessor(handler);          if (successor == null)          {             // Last handler in the chain so must deal with the request             // This is a rudimentary implementation and more complex             // logic could be applied here or perhaps in the concrete             // aspects that extend this abstract one             handler.handleRequest(request);          }           else          {             // Hand the request on to the next successor in the chain             receiveRequest(successor, request);          }       }    }    public boolean Handler.acceptRequest(Object request)    {       // The default as defined here is to reject the request       // This is implemented by the application specific       // concrete aspects       return false;    }    public void Handler.handleRequest(Object request)    {       // A default empty implementation that is overridden       // if required by the application specific concrete aspects    }    protected abstract pointcut eventTrigger(Handler handler, Object request);    after(Handler handler, Object request) : eventTrigger(handler, request)    {       receiveRequest(handler, request);    }    public void setSuccessor(Handler handler, Handler successor)    {       successors.put(handler, successor);    }    public Handler getSuccessor(Handler handler)    {       return ((Handler) successors.get(handler));    } }

Discussion

The ChainOfResponsibilityPattern abstract aspect defines the Handler interface that can then be applied by specialized subaspect to all classes within a specific application that are to participate in the chain. The aspect maintains the chain and asks the specifics of how a request is to be handled by specific subaspects.

Figure 19-15 shows the structure of the ChainOfResponsibilityPattern abstract aspect and the interfaces and behavior that it defines to support the chain of responsibility design pattern.

Figure 19-15. The ChainOfResponsibilityPattern aspect and the interfaces it defines for the design pattern's roles


Example 19-10 shows how the abstract ChainOfResponsibility aspect could be applied for a specific application.

Example 19-10. Applying the ChainOfResponsibility aspect to an application's classes
public aspect HelpChain extends ChainOfResponsibilityPattern  {    declare parents : PrintButton implements Handler;    declare parents : PrintDialog implements Handler;    declare parents : Manager implements Handler;    protected pointcut eventTrigger(Handler handler, Object event) :           call(void PrintButton.doClick(..))          && target(handler)          && args(event);    private boolean Handler.alreadyHandledRequest = false;    public boolean Handler.acceptRequest(Object event)    {       return !this.alreadyHandledRequest;    }    public void PrintButton.handleRequest(Object event)    {       if (!this.acceptRequest(event))       {          System.out.println(             "PrintButton Forced to handle Request" +             "due to being last in the chain (Implementation Decision)");       }       System.out.println("PrintButton handling request: " + event);       this.alreadyHandledRequest = true;    }    public void PrintDialog.handleRequest(Object event)    {       if (!this.acceptRequest(event))       {          System.out.println(             "PrintDialog Forced to handle Request" +             "due to being last in the chain (Implementation Decision)");       }       System.out.println("PrintDialog handling request: " + event);       this.alreadyHandledRequest = true;    }    public void Manager.handleRequest(Object event)    {       if (!this.acceptRequest(event))       {          System.out.println(             "Manager Forced to handle Request due to being" +             "last in the chain (Implementation Decision)");       }       System.out.println("Manager handling request: " + event);       this.alreadyHandledRequest = true;    } }

The HelpChain aspect in Example 19-10, as its title suggests, implements a help chain where the request for help information is passed to the classes that are registered handlers until one accepts the request or it is the last in the chain.

Figure 19-16 shows the PrintButton, PrintDialog, and Manager classes before the HelpChain aspect is applied.

Figure 19-16. The PrintButton, PrintDialog, and Manager classes


Figure 19-17 shows the effects of applying the HelpChain aspect to the PrintButton, PrintDialog, and Manager classes.

Figure 19-17. The static structure after the chain of responsibility pattern has been applied to the PrintButton, PrintDialog, and EntryField classes


Figure 19-18 shows an example interaction with the classes in Figure 19-17, using the aspect introduced chain of responsibility pattern features.

Figure 19-18. Using the chain of responsibility pattern to handle a request between the PrintButton and Manager classes


See Also

The Mediator pattern, as shown in Recipe 19.4, is often combined with the Chain Of Responsibility pattern where a common mediator is required to work with the many objects of the application using the chain of responsibility to pass requests throughout the application; more information on the extension of existing classes using aspects can be found in Recipe 16.1; the Director aspect-oriented design pattern is explained in Recipe 23.3.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net