CMPT 300 Design Patterns
Mayterm 2008
State and Patterns
State Pattern
State diagrams allow us to to abstract the notion of a system that has a
state.
An example - a simple media player that you can play, pause, and stop
One strategy for representing this in a program:
1) Determine all possible states.
enum State {PLAYING, PAUSED, STOPPED};
2) Determine all possible state transitions
public void pressPlay();
public void pressPause();
public void pressStop();
A program that represents the media player:
- RemoteDeviceV1.java
- TestDrive.java
What are the problems with this program?
Solution -> the State pattern
In UML
The above problem using the State pattern:
- State.java
- Playing.java
- Paused.java
- Stopped.java
- RemoteDevice.java
The Lab Part I
1. Initially, modify the program TestDrive.java
so that it used the new RemoteDevice class that incorporates
the State pattern.
2. Consider if we want to add a rewind button (this also sets the position
back to 0.)
Modify the program so that it allows a Rewind
state as well as a pressRewind transition.
However, notice that you can only transition to Rewind from Stopped. (Don't
forget to set the position back to zero!)
You also have to consider what state to transition to from Rewind. (In other
words, once you have rewound the media, what can you do next?) There are a
few different ways of accomplishing this, however one strategy is to consider
the following hint: It is ok to have a transition from one state to the next
that requires no action on the users part (they don't have to press any buttons.)
3. What if we added a locked feature
to our remote? When the remote is locked, we cannot press any buttons (except
to unlock it.) Modify your program so that it provides for a lock. (Be careful
here, there are a few different ways of accomplishing this .... )
Null Pattern
The Null pattern is perhaps the simplest of patterns - it does nothing!
However, the ability of an object to have default behavior that does nothing
is actually quite useful. As our motivating example, we will look at logging.
Logging is simply a technique to register certain events occurring in a
program. For example, a web server logs every requests. A database may log
all transactions so that it may rollback and restore. You might want to use
logging when debugging a program by writing messages from exceptions to a
log.
We will first present a simple logging model and then use logging as a
motivator for the Null pattern.
- Log.java
is the interface for logging.
- ConsoleLog.java
- FileLog.java
are two different implementations of the Log interface.
- Suite.java
illustrates how they work.
However, if we wanted to disable logging, we would have to do something
like:
- SuiteNoLog.java
There are other techniques, such as commenting out the call to logging.
However, they require time and introduce the possibility of unintended errors.
The Null pattern says to implement the Log interface, but do nothing.
- NullLog.java
Now, to disable logging, all we have to do is create an instance of NullLog.
- SuiteNullLog.java
In UML:
The Lab Part II
The following program simulates a hash table:
- HashTable.java
The problem is we must check for null before attempting to get an iterator
for the hash bucket.
Rewrite this program using the Null pattern. This first requires
creating a NullIterator
object. This object must implement the java.util.Iterator interface but provide no functionality
(make sure the remove() throws an UnsupportedOperationException.)
Initialize the table array with the NullIterator object (hmmm .... do we need
MAX copies of
NullIterator, or can we get by with just one?).
The code without the check for null should now work correctly.