Better Software - July/August 2008 - (Page 33) WidgetBase* wb = new NullWidget(); … if (some condition) { delete wb; wb = new RealWidget(); } … // Using it wb->method(); // No need for if (wb), etc. Listing 2 public interface LampState { public LampState turnSwitch(); } public class DimState implements LampState { public LampState turnSwitch() { return new MediumState(); } } Listing 3 If you limit yourself to GoF+1, you are sadly under-informed. In fact, in some cases, a GoF pattern may not be the best design. ment store. The cashier began to ring up the sale but then stopped and said, “I’m sorry, we have to use a different cash register. This one just went down.” I looked at the offending cash register. Emblazoned on the display was a Java message: unhandled Null Pointer exception. If the programmers who wrote that code had used Null Object, it is unlikely the cash register would have cashed out. States and Collections for States. Let’s look at the second. We often need to handle the lifecycle of objects or operate on them collectively with respect to their current state. While we view these objects with state, the objects themselves are independent of any state model. In such cases, the object should not be required to manage its own state. For example, a garbage collector may mark objects as referenced or unreferenced. However, the objects themselves should not have to know about this state information. Therefore, represent each state as a collection of objects. Each object in a collection has the associated state. An object changes state by moving from one collection to another. Each collection can easily and efficiently operate on all objects of that particular state. Put all objects on “unreferenced” list. For all objects on the “unreferenced” list: If object is referenced, move it to referenced list. For all objects still on the “unreferenced” list: Delete them (the unreferenced list is presumably short) This pattern helps keep the design of the objects unencumbered by state information. At the same time, it improves efficiency where operations on collections of objects in a state are needed. The leaky buckeT cOuNTer PaTTerN Shall we stop at GoF+2? You will find many patterns are particularly applicable to specialized domains. For example, many systems must be highly reliable and available, even in the face of real world vagaries. For example, communication software must deal with occasional link errors. A checksum error in a packet is usually a transient hiccup in the link. But many such errors indicate a real problem, and (physical) corrective measures must be taken. But how do you tell the difference between a transient fault and a real problem? It is surprisingly easy to implement a construct that differentiates between transient and real errors. You create a counter that acts as a leaky bucket [5, 6]. When the bucket is empty, you know you have a problem. Here’s how it works: You create a counter and initialize it to a predefined value. Every time you encounter a fault, you decrement the counter. However, at regular intervals you increment the counter, up to a predefined maximum value. As long as the faults are rare, the timer will keep the bucket (the counter) full. However, if faults happen frequently, the timer can’t keep up, and the bucket empties. When the counter reaches zero, take appropriate corrective action. The simplest Leaky Bucket Counter takes just a few lines of code to write, BETTER SOFTWARE The cOllecTiONs fOr sTaTes PaTTerN Now we’re up to twenty-four patterns! That’s good enough, isn’t it? Well, I’m glad you like the Null Object pattern, but if you limit yourself to GoF+1, you are sadly under-informed. In fact, in some cases, a GoF pattern may not be the best design. Let’s take the lowly State pattern, for example. The concept of the State pattern is simple: Represent the states of a system as a class hierarchy, with one class for each different state. You create the proper State object for the state you are in, and it encapsulates the behavior of how the system should respond to stimuli when in that state, as shown in listing 3. But it may not be the best solution. There are many ways to implement state-driven behavior, and using objects for states can lead to unnecessary complexity and class explosions. In fact, Frank Buschmann et al. [4] give two additional state patterns: Methods for www.StickyMinds.com JULY/AUGUST 2008 33 http://www.StickyMinds.com
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.