Functor, Command, Command Processor · 8/15/2013  · callback mechanism, but this is not available...

Preview:

Citation preview

Functor, Command, Command Processor

FunctorFunctor

FunctorsFunctors• Often when designing general-purpose software, we

k f llb k f timake use of callback functions• A callback function is a function that is made known

(registered) to the system to be called at a later time h t i twhen certain events occur

• In C and C++ we can use pointers to functions as a callback mechanism, but this is not available in Java

f• In Java we must use an object that serves the role of a pointer to a function. (We could also use this technique in C++.)A f t i l ith ll l th d h• A functor is a class with usually only one method whose instances serve the role of a pointer to a function. Functor objects can be created, passed as parameters and manipulated wherever function pointers are neededand manipulated wherever function pointers are needed.

• Coplien coined the word functor for this type of class

What is a Function Pointer?What is a Function Pointer? • Function Pointers are pointers, i.e. variables,Function Pointers are pointers, i.e. variables,

which point to the address of a functionCallback Functions• Function Pointers provide the concept of

callback functions • A callback is done just like a normal function

call would be done: – You just use the name of the function pointer instead

of a function name.

Functions as ObjectsFunctions as Objects • An object that models an operationAn object that models an operation • Functors are functions that behave like

objectsobjects• They serve the role of a function, but can

b t d d t dbe created, passed as parameters, and manipulated like objects

• A functor is a class with a single member function

Example SortingExample - Sortingclass SortedList {

private Object[] listElements; private void sortTheList() {

// use fancy sort method like quicksort blah blah if ( listElement[k] > listElement[k+j] ) {

swap or something }

} }

How do we compare Elements?How do we compare Elements?

• We don't know the type? We may wish toWe don t know the type? We may wish to sort the same objects in different ways

by name– by name– by id

by address– by address• In C++ we could use function pointers, but

t i Jnot in Java

Functor SolutionFunctor Solutionabstract class Compare {

i t t ti fi l i t LESS THAN 1private 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 ) { p g ( j , j ) {

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;

}

Functor SolutionFunctor Solutionpublic boolean equals( Object a, Object b ) {

int result = compareTo(a b );int result = compareTo(a, b ); if ( result == EQUAL_TO ) return true; else return false;

} abstract public int compareTo( Object a Object b );abstract public int compareTo( Object a, Object b );

} class CompareInt extends Compare {

public int compareTo( Object a, Object b ) { if ( (int) a < (int) b )if ( (int) a < (int) b )

return LESS_THAN; else if ( (int) a > (int) b )

return GREATER_THAN; elseelse

return EQUAL_TO; }

}

Functor SolutionFunctor Solutionclass CompareString extends Compare {

blah }

class CompareStudentRecordByID extends Compare { blah

}

class CompareStudentRecordByAddress extends Compare { blah

}

Functor SolutionFunctor Solutionclass SortedList {

private Object[] listElements; private Compare comparer; public SortedList( Compare function ) {

comparer = function;comparer = function; } private void sortTheList() {

// use fancy sort method like quicksort y qblah blah if ( comparer.lessThan(listElement[k], listElement[k+j] ) ) {

swap or something }

} }}

Example 2Example 2• Consider a Java Observable object and its Observer

bj t E h Ob i l t th Obobjects. Each Observer implements the Observer interface and provides an implementation of the update() method. As far as the Observable is concerned, it essentially has a pointer to an update() method toessentially has a pointer to an update() method to callback when Observers should be notified. So, in this case, each Observer object is acting as a functor.

• Here's an Observer:• Here s an Observer:public class NameObserver implements Observer {

public void update(Observable obj, Object arg) {//Whatever

}...

}

Example 2Example 2• And here's an Observable TheAnd here s an Observable. The

notifyObservers() method makes the callback to update()callback to update().

public class ConcreteSubject extends Observable {public void setName(String name) {

thithis.name = name;setChanged();notifyObservers(name);

}}...

}

How Does a Functor Compare to Function Pointers?• Using inheritance we can factor commonUsing inheritance we can factor common

code to a base class • Same run time flexibility as function• Same run-time flexibility as function

pointer L d it lf t b t ti• Lends it self to poor abstractions

When to use the FunctorWhen to use the Functor• Coplien states:Coplien states:

– Use functors when you would be tempted to use function pointersuse function pointers

• Functors are good for callbacks

CommandCommand

IntentIntent• Encapsulates a request as an objectEncapsulates a request as an object,

thereby letting you parameterize clients with different requests queue or logwith different requests, queue or log requests, and support undoable operationsoperations.

• Maintains a binding between a receiver and a functionand a function

• Give much more power than functor

MotivationMotivation

ProblemProblem• Need to issue requests to objects withoutNeed to issue requests to objects without

knowing anything about the operation being requested or the receiver of thebeing requested or the receiver of the request.

StructureStructure

• LetLet – Invoker be a menu

Client be a word processing program– Client be a word processing program– Receiver a document

action be save– action be save

ExampleExample• The Command pattern allows requests to be p q

encapsulated as objects, thereby allowing clients to be parameterized with different requests

• The "check" at a diner is an example of a CommandThe check at a diner is an example of a Command pattern

• The waiter or waitress takes an order or command from a customer and encapsulates that order by writing it ona customer and encapsulates that order by writing it on the check

• The order is then queued for a short order cook.• Note that the pad of "checks" used by each waiter is not

dependent on the menu, and therefore they can support commands to cook many different items.y

When to Use the Command Pattern• When you need an action as a parametery p

– Commands replace callback functions• When you need to specify, queue, and execute requests

at different timesat 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 p g– Systems that use transaction often can use the command

pattern• When you need to support a macro languagey pp g g

ConsequencesConsequences • Command decouples the object thatCommand decouples the object that

invokes the operation from the one that knows how to perform itknows how to perform it

• It is easy to add new commands, because you do not have to change existingyou do not have to change existing classes Y bl d i t• You can assemble commands into a composite object

Example Menu CallbacksExample - Menu Callbacks abstract class Command {

abstract public void execute();abstract public void execute(); } class OpenCommand extends Command {

private Application opener; public OpenCommand( Application theOpener ) {public OpenCommand( Application theOpener ) {

opener = theOpener; } public void execute() {

String documentName = AskUserSomeHow();String documentName = AskUserSomeHow(); if ( name != null ) {

Document toOpen = new Document( documentName ); opener.add( toOpen ); opener open();opener.open();

} }

}

Using CommandUsing Commandclass 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

}

MacroCommandMacroCommand

MacroCommandMacroCommandclass MacroCommand extends Command {

private Vector commands = new Vector();private Vector commands = new Vector(); public void add( Command toAdd ) {

commands.addElement( toAdd ); } public void remove( Command toRemove ) {public void remove( Command toRemove ) {

commands.removeElement( toAdd ); } public void execute() {

Enumeration commandList = commands elements();Enumeration commandList = commands.elements(); while ( commandList.hasMoreElements() ) {

Command nextCommand; nextCommand = (Command) commandList.nextElement();nextCommand execute();nextCommand.execute();

} }

}

Example 2Example 2• Situation: A GUI system has several buttons that perform

i ti W t t h it th tvarious actions. We want to have menu items that perform the same action as its corresponding button.

• Solution 1: Have one action listener for all buttons and it A li thi i t d l timenu items. As seen earlier, this is not a good solution

as the resulting actionPerformed() method violates the Open-Closed Principle.Solution 2: Have an action listener for each paired button• Solution 2: Have an action listener for each paired button and menu item. Keep the required actions in the actionPerformed() method of this one action listener. This solution is essentially the Command pattern withThis solution is essentially the Command pattern with simple ConcreteCommand classes that perform the actions themselves, acting like functors

• In Java 2, Swing Action objects are used for this purposeIn Java 2, Swing Action objects are used for this purpose

Swing ActionsSwing Actions• A Swing Action object is really just an g j y j

ActionListener object that not only provides the ActionEvent handling, but also centralized handling of the text, icon, and enabled state of g , ,toolbar buttons or menu items

• The same Action object can easily be associated with a toolbar button and a menu itemwith a toolbar button and a menu item

• The Action object also maintains the enabled state of the function associated with the toolbar b i d ll li bbutton or menu item and allows listeners to be notified when this functionality is enabled or disabled

Swing ActionsSwing Actions• In addition to the actionPerformed method defined by the

A ti Li t i t f bj t th t i l t thActionListener interface, objects that implement the Action interface provide methods that allow the specification of:

One or more text strings that describe the function of the button– One or more text strings that describe the function of the button or menu item

– One or more icons that depict the function– The enabled/disabled state of the functionalitye e ab ed/d sab ed state o t e u ct o a ty

• By adding an Action to a JToolBar or JMenu, you get:– A new JButton (for JToolBar) or JMenuItem (for JMenu ) that is

automatically added to the tool bar or menu. The button or menu i i ll h i d ifi d b h A iitem automatically uses the icon and text specified by the Action.

– A registered action listener (the Action object) for the button or menu item

– Centralized handling of the button's or menu item's enabled stateCentralized handling of the button s or menu item s enabled state

Swing Actions ExampleSwing Actions Example/*** Cl S i A ti d t t th C d P tt* Class SwingActions demonstrates the Command Pattern* using Swing Actions.*/public class SwingActions extends JFrame {p g {

private JToolBar tb;private JTextArea ta;private JMenu fileMenu;private Action openAction;private Action openAction;private Action closeAction;public SwingActions() {

super("SwingActions");setupGUI();

}

Swing Actions ExampleSwing Actions Exampleprivate void setupGUI() {

//C t th t lb d//Create the toolbar and menu.tb = new JToolBar();fileMenu = new JMenu("File");//Create the text area used for output.pta = new JTextArea(5, 30);JScrollPane scrollPane = new JScrollPane(ta);//Layout the content pane.JPanel contentPane = new JPanel();JPanel contentPane = new JPanel();contentPane.setLayout(new BorderLayout());contentPane.setPreferredSize(new Dimension(400, 150));contentPane.add(tb, BorderLayout.NORTH);contentPane.add(scrollPane, BorderLayout.CENTER);setContentPane(contentPane);

Swing Actions ExampleSwing Actions Example//Set up the menu bar.JM B b JM B ()JMenuBar mb = new JMenuBar();mb.add(fileMenu);setJMenuBar(mb);// Create an action for "Open".pImageIcon openIcon = new ImageIcon("open.gif");openAction = new AbstractAction("Open", openIcon) {

public void actionPerformed(ActionEvent e) {ta append("Open action from " + e getActionCommand() +"\n");ta.append( Open action from + e.getActionCommand() + \n );

}};// Use the action to add a button to the toolbar.JButton openButton = tb.add(openAction);openButton.setText("");openButton.setActionCommand("Open Button");openButton setToolTipText("This is the open button");openButton.setToolTipText( This is the open button );

Swing Actions ExampleSwing Actions Example// Use the action to add a menu item to the file menu.JM It M It fil M dd( A ti )JMenuItem openMenuItem = fileMenu.add(openAction);openMenuItem.setIcon(null);openMenuItem.setActionCommand("Open Menu Item");// Create an action for "Close" and use the action to add// a button to the toolbar and a menu item to the menu.// Code NOT shown - similar to "open" code above.

}public static void main(String[] args) {public static void main(String[] args) {

SwingActions frame = new SwingActions();frame.pack();frame.setVisible(true);

}}

Another ExampleAnother Example• Scenario: We want to write a class that canScenario: We want to write a class that can

periodically execute one or more methods of various objects. For example, we want to run a backup operation every hour and a disk status operation every ten minutes. But we do not want th l t k th d t il f th tithe class to know the details of these operations or the objects that provide them. We want to decouple the class that schedules the executiondecouple the class that schedules the execution of these methods with the classes that actually provide the behavior we want to execute.p

• Solution: The Command Pattern!Solution: The Command Pattern!

• Here’s the Task interface:public interface Task {public interface Task {

public void performTask();}

• Instead of a BackupTask or DiskStatusClass, here is a simple Fortune Teller Task which cycles through a list of fortuneFortune Teller Task which cycles through a list of fortune sayings:

public class FortuneTask implements Task {p p {int nextFortune = 0;String[] fortunes = {"She who studies hard, gets A",

"Seeth the pattern and knoweth the truth","He who leaves state the day after final graduates not" };He who leaves state the day after final, graduates not };

public FortuneTask() {}public void performTask() {

System.out.println("Your fortune is: " + fortunes[nextFortune]);nextFortune = (nextFortune + 1) % fortunes.length;

}public String toString() {return ("Fortune Telling Task");}

}}

• And here is a Fibonacci Sequence Task which generates a sequence of Fibonacci numbers:of Fibonacci numbers:

public class FibonacciTask implements Task {int n1 = 1;int n2 = 0;int num;public FibonacciTask() {}public void performTask() {

num = n1 + n2;num n1 + n2;System.out.println("Next Fibonacci number is: " + num);n1 = n2;n2 = num;

}}public String toString() {return ("Fibonacci Sequence Task");}

}

• Here is the TaskEntry class:Here is the TaskEntry class:public class TaskEntry {

private Task task // The task to be done It's a Command object!i t l tI t l // H ft t k h ld b t dprivate long repeatInterval; // How often task should be executed

private long timeLastDone; // Time task was last donepublic TaskEntry(Task task, long repeatInterval) {

this.task = task;this.repeatInterval = repeatInterval;this timeLastDone = System currentTimeMillis();this.timeLastDone System.currentTimeMillis();

}public Task getTask() {return task;}

public void setTask(Task task) {this.task = task;}bli l tR tI t l() { t tI t l }public long getRepeatInterval() {return repeatInterval;}

public void setRepeatInterval(long ri) {this.repeatInterval = ri;

}}public long getTimeLastDone() {return timeLastDone;}public void setTimeLastDone(long t) {this.timeLastDone = t;}public String toString() {

return (task + " to be done every " + repeatInterval + " ms; last done " +return (task + to be done every + repeatInterval + ms; last done + timeLastDone);

}}

• Here is the TaskMinder class:bli l T kMi d t d Th d {public class TaskMinder extends Thread {

private long sleepInterval; // How often the TaskMinder should// check for tasks to be run

private Vector taskList; // The list of tasksp ;public TaskMinder(long sleepInterval, int maxTasks) {

this.sleepInterval = sleepInterval;taskList = new Vector(maxTasks);start();start();

}public void addTask(Task task, long repeatInterval) {

long ri = (repeatInterval > 0) ? repeatInterval : 0;TaskEntry te = new TaskEntry(task, ri);taskList.addElement(te);

}

public Enumeration getTasks() {return taskList.elements();}bli l tSl I t l() { t l I t l }public long getSleepInterval() {return sleepInterval;}

public void setSleepInterval(long si) {this.sleepInterval = si;

}}public void run() {

while (true) {try {

sleep(sleepInterval);sleep(sleepInterval);long now = System.currentTimeMillis();Enumeration e = taskList.elements();

while (e.hasMoreElements()) {T kE (T kE ) El ()TaskEntry te = (TaskEntry) e.nextElement();

if (te.getRepeatInterval() + te.getTimeLastDone() < now) {te.getTask().performTask();te setTimeLastDone(now);te.setTimeLastDone(now);

} }

}}catch (Exception e) {

System.out.println("Interrupted sleep: " + e);}}

}}

}

• Test program:Test program:public class TestTaskMinder {

public static void main(String args[]) {// C t d t t T kMi d// Create and start a TaskMinder.// This TaskMinder checks for things to do every 500 ms// and allows a maximum of 100 tasks.TaskMinder tm = new TaskMinder(500, 100);// Create a Fortune Teller Task.FortuneTask fortuneTask = new FortuneTask();FortuneTask fortuneTask new FortuneTask();// Have the Fortune Teller execute every 3 seconds.tm.addTask(fortuneTask, 3000);

// Create a Fibonacci Sequence Task.FibonacciTask fibonacciTask = new FibonacciTask();// Have the Fibonacci Sequence execute every 700// milliseconds.// milliseconds.tm.addTask(fibonacciTask, 700);

}}}

• Test program output:N t Fib i b i 1Next Fibonacci number is: 1Next Fibonacci number is: 1Your fortune is: She who studies hard, gets ANext Fibonacci number is: 2N t Fib i b i 3Next Fibonacci number is: 3Next Fibonacci number is: 5Next Fibonacci number is: 8Your fortune is: Seeth the pattern and knoweth the truthN t Fib i b i 13Next Fibonacci number is: 13Next Fibonacci number is: 21Next Fibonacci number is: 34Your fortune is: He who leaves state the day after final, graduates notN t Fib i b i 55Next Fibonacci number is: 55Next Fibonacci number is: 89Next Fibonacci number is: 144etc.

Command ProcessorCommand Processor

Command ProcessorCommand Processor • The Command Processor pattern is similar to the p

command pattern• Command Processor covers how the command objects

are managedare managed • In the Command Processor, a command processor

object handles all command objects Th d• 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 ensure only one instance

StructureStructure

DynamicsDynamics

Consequences: BenefitsConsequences: Benefits• Flexibility in the way requests are activated

Diff t i t f l t t th ki d f– 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• 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

Consequences: LiabilitiesConsequences: Liabilities• Efficiency lossEfficiency 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

• ComplexityComplexity – How do commands get additional parameters they

need?

Study YourselfStudy Yourself• Implementing a Pattern Library in the RealImplementing a Pattern Library in the Real

World: A Yahoo! Case Study by Erin Malone Matt Leacock Chanel WheelerMalone, Matt Leacock, Chanel Wheeler – http://www.boxesandarrows.com/view/implem

enting a pattern library in the real world aenting_a_pattern_library_in_the_real_world_a_yahoo_case_study

Recommended