CMPT 300 Design Patterns
Mayterm 2008

State and Patterns


<< lab8.zip >>

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

State Diagram

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 State Pattern


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.)

rewind



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.