SDSU CS 635: Advanced Object-Oriented Design & Programming
Spring Semester, 1998
Functor, Command, Command Processor

To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98

Contents of Doc 16, Functor, Command, Command Processor


References slide # 1
Functor slide # 2
Command slide # 7
...Structure slide # 7
Command Processor slide # 12
...Structure slide # 13
...Dynamics slide # 13
...Consequences slide # 14


References


Design Patterns: Elements of Resuable Object-Oriented Software, Gamma, Helm, Johnson, Vlissides, Addison-Wesley, 1995, pp 233-242, Command Pattern

Advanced C++: Programming Styles and Idioms, James Coplien, Addison Wesley, 1992, pp 165-170, Functor Pattern

Pattern-Oriented Software: A System of Patterns, Buschman, Meunier, Rohnert, Sommerlad, Stal, 1996, pp 277-290, Command Processor

Command Processor, Sommerlad in Pattern Languages of Program Design 2, Eds Vlissides, Coplien, Kerth, Addison-Wesley, 1996, pp 63-74,


Doc 16, Functor, Command, Command Processor Slide # 2

Functor

Functions as Objects

Functors are functions that behave like objects

They serve the role of a function, but can be created, passed as parameters, and manipulated like objects

A functor is a class with a single member function


Example - Sorting

class SortedList
     {
     private Object[] listElements;
     
     private void sortTheList()
          {
          // use fancy sort method like quicksort
          blah
          blah
          
          if ( listElement[k] > listElement[k+j] )
               {
               swap or something
               }
          }
     }



Doc 16, Functor, Command, Command Processor Slide # 3
How do we compare Elements?

We don't know the type?

We may wish to sort the same objects in different ways

by name
by id
by address
In C++ we could use function pointers, but not in Java


Functor Solution

abstract class Compare
     {
     private static final int LESS_THAN = -1;
     private static final int GREATER_THAN = 1;
     private static final int EQUAL_TO = 0;
     
     public boolean greaterThan( Object a, Object b )
          {
          int result = compareTo( a, b );
          if ( result == GREATER_THAN ) return true;
          else return false;

     public boolean lessThan( Object a, Object b )
          {
          int result = compareTo( a, b );
          if ( result == LESS_THAN ) return true;
          else return false;
          }

Doc 16, Functor, Command, Command Processor Slide # 4

public boolean equals( Object a, Object b )
          {
          int result = compareTo(a,  b );
          if ( result == EQUAL_TO ) return true;
          else return false;
          }

     abstract public int compareTo( Object a, Object b );
     }
     
class CompareInt extends Compare
     {
     public int compareTo( Object a, Object b )
          {
          if ( (int) a < (int) b )
               return LESS_THAN;
          else if  ( (int) a > (int) b )
               return GREATER_THAN;
          else
               return EQUAL_TO;
          }
     }

class CompareString extends Compare
     { blah }

class CompareStudentRecordByID extends Compare
     { blah }

class CompareStudentRecordByAddress extends Compare
     { blah }


Doc 16, Functor, Command, Command Processor Slide # 5
class SortedList
     {
     private Object[] listElements;
     private Compare comparer;
     
     public SortedList( Compare function )
          {
          comparer = function;
          }
          
     private void sortTheList()
          {
          // use fancy sort method like quicksort
          blah
          blah
          
          if ( comparer.lessThan(listElement[k], listElement[k+j] ) )
               {
               swap or something
               }
          }
     }


Doc 16, Functor, Command, Command Processor Slide # 6
How Does a Functor Compare to Function Pointers?

Using inheritance we can factor common code to a base class

Same run-time flexibility as function pointer

Lends it self to poor abstractions

Other?

When to use the Functor

Coplien states:
Use functors when you would be tempted to use function pointers

Functors are good for callbacks


Doc 16, Functor, Command, Command Processor Slide # 7

Command


Maintains a binding between a receiver and a function

Give much more power than functor

Structure


Command Pattern Structure

Example

Let

Invoker be a menu
Client be a word processing program
Receiver a document
action be save

Doc 16, Functor, Command, Command Processor Slide # 8
When to Use the Command Pattern

When you need an action as a parameter
Commands replace callback functions

When you need to specify, queue, and execute requests at different times

When you need to support undo

When you need to support logging changes

When you structure a system around high-level operations built on primitive operations

A Transactions encapsulates a set of changes to data

Systems that use transaction often can use the command pattern

When you need to support a macro language

Consequences
Command decouples the object that invokes the operation from the one that knows how to perform it

It is easy to add new commands, because you do not have to change existing classes

You can assemble commands into a composite object


Doc 16, Functor, Command, Command Processor Slide # 9
Example - Menu Callbacks

abstract class Command
     {
     abstract public void execute();
     }
     
class OpenCommand extends Command
     {
     private Application opener;
     
     public OpenCommand( Application theOpener )
          {
          opener = theOpener;
          }
     
     public void execute()
          {
          String documentName = AskUserSomeHow();
          
          if ( name != null )
               {
               Document toOpen = 
                         new Document( documentName );
               opener.add( toOpen );
               opener.open();
               }
          }
     }

Doc 16, Functor, Command, Command Processor Slide # 10
Using Command

class Menu
     {
     private Hashtable menuActions = new Hashtable();
     
     public void addMenuItem( String displayString, 
                              Command itemAction )
          {
          menuActions.put( displayString, itemAction );
          }

     public void handleEvent( String itemSelected )
          {
          Command runMe;
          runMe = (Command) menuActions.get( itemSelected );
          runMe.execute();
          }

     // lots of stuff missing
     }


Doc 16, Functor, Command, Command Processor Slide # 11
MacroCommand

class MacroCommand extends Command
     {
     private Vector commands = new Vector();
     
     public void add( Command toAdd )
          {
          commands.addElement( toAdd );
          }

     public void remove( Command toRemove )
          {
          commands.removeElement( toAdd );
          }
     
     public void execute()
          {
          Enumeration commandList = commands.elements();
          
          while ( commandList.hasMoreElements() )
               {
               Command nextCommand;
               nextCommand = (Command)
                                    commandList.nextElement();
               nextCommand.execute();
               }
          }
     }


Doc 16, Functor, Command, Command Processor Slide # 12

Command Processor


The Command Processor pattern is similar to the command pattern

Command Processor covers how the command objects are managed

In the Command Processor, a command processor object handles all command objects

The command processor:

contains all command objects

schedules the execution of commands

may store the commands for later undo

may log the sequence of commands for testing purposes

uses singleton to insure only one instance


Doc 16, Functor, Command, Command Processor Slide # 13

Structure

Command Processor Structure

Dynamics

Command Processor Dynamics

Doc 16, Functor, Command, Command Processor Slide # 14

Consequences

Benefits

Flexibility in the way requests are activated

Different user interface elements can generate the same kind of command object

Allows the user to configure commands performed by a user interface element

Flexibility in the number and functionality of requests

Adding new commands and providing for a macro language comes easy

Programming execution-related services

Commands can be stored for later replay
Commands can be logged
Commands can be rolled back

Testability at application level

Concurrency

Allows for the execution of commands in separate threads


Doc 16, Functor, Command, Command Processor Slide # 15
Liabilities

Efficiency loss

Potential for an excessive number of command classes

Try reducing the number of command classes by:

Grouping commands around abstractions

Unifying simple commands classes by passing the receiver object as a parameter


Complexity

How do commands get additional parameters they need?

visitors since 17-Mar-98