Saturday, February 28, 2009

Challenge Two - State Design Pattern

In Programming Without Ifs Challenge One we identified the varying behavior which depended on the state of the calculator, and abstracted it with the introduction of a Strategy Design Pattern. Then when the calculator switched from the pre-operator mode to the post-operator mode, the calculator model also switched to the appropriate strategy. Thus, the calculator model was not kept in a state of ignorance. It didn't need to employ conditional logic to ask itself what state it was in to decide what to do - it already knew. The logic for switching between the strategies, ie., knowing when a change of state occurred and what to do about it, stayed on the calculator model. Our refactoring just implemented it in a different way. In Programming Without Ifs Challenge Two, we use the State Design Pattern, which moves the knowledge for what to do to the classes that characterize the state machine. Challenge Two involves programming a stopwatch.

Consider the scheme of the stopwatch interface shown below.


The stopwatch is started by clicking on the Start/Stop button. The watch is started as evidenced by the time label and the 'HOLD' button is activated. The watch can now be stopped or suspended as shown in the figure below.


The suspended mode is for timing splits. By clicking on the 'HOLD' button again, the watch will catch up to it's original timing and subsequent suspensions can again occur indefinitely. The watch can be stopped by clicking on 'START/STOP' from either the suspended mode or the running mode. After stopping the watch, the 'RESET' button will be activated as shown below.


After clicking on 'RESET' the watch will return to its starting mode as shown in the first schematic. A state diagram for the stopwatch is shown below.


Download for the code for the stopwatch with conditional logic and refactor such that no conditional logic is used to manage the state dependencies of the application. It may be necessary to create more states than shown in the state diagram above.

Tuesday, February 24, 2009

Challenge One Answer & Discussion

To follow the discussion, download the refactored code from here.

In the refactored SwingCalculatorWithoutIfs, the conditional logic originally encountered in the JFrame is now replaced by giving to each button the responsibility for listening to itself. In general this is a good practice for GUI design. The frame or panel holding the components shouldn’t bear the responsibility for determining what is happening such as which button has been selected and hence, what method to invoke. These types of responsibilities are the domain of the objects themselves. Thus the buttons now have the responsibility for knowing when they’ve been selected and also what to do after they’ve been selected.

The second location where conditional logic was employed was in the CalculatorModel class itself. When numbers are entered into the calculator, it must be known whether the computation is in the pre-operator or post-operator mode. In the CalculatorModel class, the numberHit method is invoked whenever a number button has been hit by the user. Conditional logic is used to determine which mode the calculator is in, the pre-operator or the post-operator mode. A purist may argue that the use of any conditional logic statement violates a rule of object-oriented programming - that a method should only do one thing. Any conditional logic structure does at least two things: (1) determine the state of the Boolean conditional; and (2) do what needs to be done pending the result. Another way to think about this is to consider that whenever an object needs to ask itself, “What state am I in?” one must wonder why the object didn’t determine what it was to do when the state variable was changed. Why is it necessary to go back in time? Why is the object ignorant of both the state it is currently in and even worse, what to do about it? In the CalculatorModel class, the solution was to use a Strategy Design Pattern.

In the words of Shalloway (2005) we “find what varies and encapsulate it.” Although this sentiment appeared in the classic “Gang-of-Four” book (Gamma, 1990), it was Shalloway who stated the commonly used adage noted above. What’s varying here? The behavior of the numberHit method, depending on the mode the calculator is in. So, we create an interface named CalculatorStrategy that abstracts the numberHit method and we create two classes, PreOperatorStrategy and PostOperatorStrategy that provide concrete implementations for the method’s behavior in pre-operator and post-operator modes, respectively. In addition to instantiating these two strategies as CalculatorStrategy types, I also create a reference to a CalculatorStrategy type named currentStrategy. This will be set to whatever strategy is appropriate as determined by the changes in state of the CalculatorModel class. To complete the control of the strategy implementation, we include statements in the rememberOperator method, which is invoked when an operator button is hit, and the reset method, which is invoked when the equals button is hit, to assign the appropriate strategy to the currentStrategy. Now, we refactor the numberHit method in the CalculatorModel to invoke currentStrategy.numberHit and since the currentStrategy has already been adjusted to behave according to whatever state the calculator is in, there is no need to inquire as to its own state. The numberHit method is now loosely coupled to the implementation of the behaviors. The numberHit method doesn’t know how it is being implemented, it only knows that it is invoking a numberHit method on a CalculatorStrategy type class and therefore, the numberHit method must be implemented.

Lastly, one more ‘if’ to eliminate. When the equals button is hit, the operate method on the CalculatorModel is invoked which in turn invokes the reset method to prepare the calculator for a new computation. The reset method sets the value of the operator property to null. To avoid throwing a NullPointerException as a result of the user hitting the equals button before selecting an operator, we use conditional logic to check whether the value of operator property is null first before we try to invoke the operate method on it. The refactored SwingCalculator has eliminated this problem by creating an inner class named NullOperator that implements the OperatorButton interface but does nothing when the operate method is invoked. When the calculator is now reset, we set the operator property to NullOperator thus obviating the need to use conditional logic to check for a null value as described above.

REFERENCES:

Gamma, E., Helm,E., Johnson, R., and John Vlissides (1990) Design Patterns: Elements of Reusable Object-Oriented Software [ISBN 0201633612]
Shalloway, A., and Trott, J.R., (2005) Design Patterns Explained: A New Perspective on Object-Oriented Design [ISBN 0321247140]

Monday, February 23, 2009

Challenge One: Bergin Swing Calculator

During the time between 2005-2009 I began my software design courses with a problem I call the “Bergin Calculator Problem” (Inspired by Joe Bergin’s Polymorphic Calculator). It requires the student to program a simple calculator with only six buttons. Three number buttons (2,3,5) , two operator buttons (+,-) and an equals button. The calculator need only perform one binary operation before yielding an answer following a strike on the equals button. A typical computation would involve entering 2, 2, +, 3, 3, = … and the display would indicate the answer of 55. The display would show the numbers entered in both the pre-operator and post-operator modes, but not the operator itself. Thus, one would only ever see numbers in the display. Following each computation, striking the equals button would also render the calculator ready for a subsequent computation with an entirely new set of numbers.
Over ninety per cent of the submissions I graded used conditional logic to solve the problem. The week following, the class would go through the problem and together, construct a calculator that uses no conditional logic nor loop structures. The fact that this exercise amazes many students, indicates the very real possibility that most have been taught how to use an object-oriented language to do procedural programming - a very easy thing to do. In fact, I recall one graduate student who had taken the problem back to his work place and one of his co-workers, literally a rocket scientist, said the problem couldn’t be solved without the use of if’s. Since then, I have taken to giving problems to students that require them to produce a solution not dependent on conditional logic – I call this “Programming without if’s.”
I will discuss in another place the problem of over-engineering but for now assume it’s OK, in fact desirable, to construct an over-engineered solution. Why? The metaphor I like to use is that of the toolbox. When you go to your toolbox and see only a hammer, then every problem appears to be a nail. Most contemporary programmers were taught by procedural programmers whose only adaptation to learning object-oriented programming was to begin using an object-oriented language. One way to break out of this mental trap is to solve some problems without reaching for the hammer, which in the programmer’s case is the conditional logic structure.
Do I expect programmers to avoid using conditional logic as a best practice? No, the student of programming has to understand the difference between what we do to expand our capabilities, ie., put more tools in the toolbox, and what we do when programming professionally. Programming without if’s will expand your ability to see alternatives in the power offered to you by the object-oriented paradigm. If you’d like to take the Calculator Challenge a zipped Eclipse project named SwingCalculatorWithIfs is here. I will post a solution at the same address.