Functor | slide # 1 |
Command | slide # 6 |
Template Method | slide # 10 |
Advanced C++: Programing Styles and Idioms, James Coplien, Addison Wesley, 1992
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
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 } } }
We may wish to sort the same objects in different ways
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; }
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 }
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 } } }
Same run-time flexibility as function pointer
Lends it self to poor abstractions
Other?
Give much more power than functor
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(); } } }
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 }
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(); } } }
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
class Account { public: void virtual Transaction(float amount) { balance += amount;} Account(char* customerName, float InitialDeposit = 0); protected: char* name; float balance; } class JuniorAccount : public Account { public: void Transaction(float amount) {// put code here} } class SavingsAccount : public Account { public: void Transaction(float amount) {// put code here} } Account* createNewAccount() { // code to query customer and determine what type of // account to create }; main() { Account* customer; customer = createNewAccount(); customer->Transaction(amount);
class Account { public: void virtual Transaction() = 0; } class JuniorAccount : public Account { public void Transaction() { put code here} }
class Account { public: void Transaction(float amount); void virtual TransactionSubpartA(); void virtual TransactionSubpartB(); void virtual TransactionSubpartC(); } void Account::Transaction(float amount) { TransactionSubpartA(); TransactionSubpartB(); TransactionSubpartC(); // EvenMoreCode; } class JuniorAccount : public Account { public: void virtual TransactionSubpartA(); } class SavingsAccount : public Account { public: void virtual TransactionSubpartC(); } Account* customer; customer = createNewAccount(); customer->Transaction(amount);
Account* customer; customer = createNewAccount(); customer->Transaction(amount);
Account* customer;
customer = createNewAccount();
customer->Foo(); // compile error