In the MUD Game sample package, a user can send a message to an object, triggering the listen
event on the object. Yesterday, we saw the Dog.listen script which checked if the
first word was "go" and if so, attempted to wander in the direction specified.
There are two problems with the current implementation. One is within classes. If the Dog
wanted to understand several different types of commands, you'd have to have a long listen script
with lots of if statements checking the various conditions. This can be both ugly and difficult to
maintain.
The other problem is between classes. If two classes in different hierarchies want to listen to the
same command in the same way, the code must be either duplicated or extracted into a method on
the RealObject class where it doesn't really belong.
To resolve these problems, we will develop an interface called Listener. Objects in classes which
implement this interface wait for specific commands and take actions based on those commands.
Each RealObject can add whatever Listeners it wants and the driver code will call them in order
until it finds one which understands the command. Named Listeners can be used for code which
may be shared between classes and anonymous Listeners for code within one class.
If possible, please bring to recitation a laptop with the existing package.
Coding specs:
/*** New classes and methods ***/
interface Listener {
/**
Get a command and execute it if we understand it.
@param command a string such as "go north" or "take fluffy"
@param actor the creature which is acting on the command
@return true if understood
*/
public boolean listen (String command, RealObject actor);
}
class FirstWordListener implements Listener {
/**
Waits for a command beginning with a given word and passes the rest of the command to
a sub-listener.
@param firstWord the word which must begin any commands we process. Not case-
sensitive
@param sub a listener which will be called if the command matches
*/
FirstWordListener (String firstWord, Listener sub);
/**
If the first word of the command matches our defined firstWord, call our sub-listener,
passing in the rest of the command. Otherwise, return false.
*/
public boolean listen (String command, RealObject actor);
}
/**
A Listener which displays a static message
*/
class DefaultListener implements Listener {
/**
@param dunno a message to be displayed when this Listener is invoked, such as "Bow
wow" or (if you do the extension suggested below) "What do you mean by '@?'"
*/
DefaultListener (String dunno);
/**
Display a message such as "I don't understand"
@param command ignored in this implementation (but you could replace '@' contained in
the dunno string with the command)
@param actor the creature doesn't understand the command
@return always true
*/
public boolean listen (String command, RealObject actor);
}
class RealObject
/**
Add a listener which may process commands we hear via the listen method.
@param l the Listener to add
@param position where to add the Listener (beginning or end)
*/
protected void addListener (Listener l, int position)
/*** Changes to existing methods ***/
/*
Replace the existing implementation with code which loops through all of our Listeners, calling
each in turn until one returns true.
*/
...listen (...)
/*
Add code which adds a DefaultListener that always displays "I don't understand"
*/
...initialize (...)
class Dog
/*
Add code which adds appropriate listeners that mimic the current behavior of the Dog. Use a
named Listener so you can re-use it for the Toddler.
*/
...initialize (...)
/*
Remove the overridden method
*/
...listen (...)
class Toddler
/*
Add code which adds four listeners:
1) Same as the go... listener for the dog
2) If the first word of the command is "say," repeats the rest of the command
3) If the command contains the word "train," replies "choo-choo"
4) Otherwise, says "No."
*/
...initialize(...)