Recipe19.2.Implementing the Command Pattern


Recipe 19.2. Implementing the Command Pattern

Problem

You want to apply the command pattern using AspectJ.

Solution

The command design pattern supports the encapsulation of requests as objects within their own right. Single or multiple operations can be combined into a request or transaction depending on their purpose. Once the request object has been constructed, it can be managed as a separate entity from the originating object.

Example 19-3 uses the Director aspect-oriented design pattern (see Chapter 23) to provide an abstract aspect that can be used to apply the command pattern.

Example 19-3. Defining the command pattern using aspects
public abstract aspect CommandPattern  {    public interface Command    {       public void executeCommand(CommandReceiver receiver);       public boolean isExecutable( );    }    public interface CommandInvoker    {    }    public interface CommandReceiver    {    }    private WeakHashMap mappingInvokerToCommand = new WeakHashMap( );    public Object setCommand(CommandInvoker invoker, Command command)    {       return mappingInvokerToCommand.put(invoker, command);    }    public Object removeCommand(CommandInvoker invoker)    {       return setCommand(invoker, null);    }    public Command getCommand(CommandInvoker invoker)    {       return (Command) mappingInvokerToCommand.get(invoker);    }    private WeakHashMap mappingCommandToReceiver = new WeakHashMap( );    public Object setReceiver(Command command, CommandReceiver receiver)    {       return mappingCommandToReceiver.put(command, receiver);    }    public CommandReceiver getReceiver(Command command)    {       return (CommandReceiver) mappingCommandToReceiver.get(command);    }    protected abstract pointcut commandTrigger(CommandInvoker invoker);    after(CommandInvoker invoker) : commandTrigger(invoker)    {       Command command = getCommand(invoker);       if (command != null)       {          CommandReceiver receiver = getReceiver(command);          command.executeCommand(receiver);       } else       {          // Do nothing: This Invoker has no associated command       }    }    protected pointcut setCommandTrigger(CommandInvoker invoker,                                          Command command);    after(CommandInvoker invoker, Command command) : setCommandTrigger(                                                     invoker, command)    {       if (invoker != null)          setCommand(invoker, command);    }    protected pointcut removeCommandTrigger(CommandInvoker invoker);    after(CommandInvoker invoker) : removeCommandTrigger(invoker)    {       if (invoker != null)          removeCommand(invoker);    }    public boolean Command.isExecutable( )    {       return true;    } }

Discussion

The CommandPattern abstract aspect defines the mechanisms by which the roles of a CommandInvoker , a Command, and a CommandReceiver can be set up and interact with each other. These abstract roles are assigned to application specific classes by specialized subaspects.

Figure 19-5 shows the structure of the CommandPattern abstract aspect and the interfaces and behavior that it defines to support the command design pattern.

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


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

Example 19-4. Applying the CommandPattern aspect to an application's classes
public aspect ConcreteCommand extends CommandPattern  {    declare parents : TimedEvent implements CommandInvoker;    declare parents : Printer implements CommandReceiver;    declare parents : VCardPrinter implements CommandReceiver;    declare parents : BusinessCard implements Command;    public void BusinessCard.executeCommand(CommandReceiver receiver)    {       if (receiver instanceof Printer)       {          ((Printer) receiver).println(this.toString( ));       } else       {          ((VCardPrinter) receiver).printVCard(this);       }    }    public void executeCommand(CommandReceiver receiver)    {       ((Printer) receiver).println("Command triggered on printer receiver");    }    protected pointcut commandTrigger(CommandInvoker invoker) :        call(void TimedEvent.timedOut( ))       && target(invoker); }

Figure 19-6 shows an example set of application classes before the ConcreteCommand aspect is applied. The TimerTask class is used from the Java standard libraries and supports the TimedEvent class in executing at timed intervals.

Figure 19-6. The Printer, VCardPrinter, TimedEvent, and BusinessCard classes


Figure 19-7 shows the effects of applying the ConcreteCommand aspect to the TimedEvent, Printer, VCardPrinter, and BusinessCard classes.

Figure 19-7. The static structure after the command pattern has been applied to the TimedEvent, Printer, VCardPrinter, and BusinessCard classes


Figure 19-8 shows how the new command pattern behavior of the application's classes interact with in an example application.

Figure 19-8. Using the command pattern characteristics of the TimedEvent, BusinessCard, and VCardPrinter classes


See Also

The recipes in Chapter 16 contain more details on the mechanisms by which existing classes can be extended using aspects and the declare keyword; aspects and inheritance are covered in Recipe 15.1; the after( ) form of advice is examined in Recipe Recipe 13.5; 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