1 - Kasetsart University



Objectives |Use the Command and Strategy patterns to write a calculator without any "if" statements. | |

|Prerequisites |Read chapter 6 of the textbook. |

|Evaluation |The goal is to learn. No evaluation will be performed. |

A Simple Calculator

A Simple Calculator is like the Windows "calc" program. It has two registers for holding numbers, and can perform operations like "+", "-", "*".

What happens when you enter "23 + 15 =" on a calculator? Try Windows "calc" to understand. It maybe something like this:

|Key Press (input) |Current Register |Operator |Save Register |

|initial state |0 | | |

|2 |2 | | |

|3 |23 | | |

|+ |23 |+ | |

|1 |1 |+ |23 |

|5 |15 |+ |23 |

|= |38 |none |?? |

What happens if you enter "10 + 5 - 7 ="? Complete the table below:

|Key Press (input) |Current Register |Operator |Save Register |

|initial state | | | |

| | | | |

| | | | |

| | | | |

| | | | |

| | | | |

| | | | |

| | | | |

Task 1: A Simple, Observable Calculator

Download SimpleCalculator.zip from the "lab" directory and create a Java project in your IDE.

Calculator.java implements the logic of a calculator. It is Observable.

Console.java handles user input and gives it to the calculator.

Display.java displays whatever is in the current register. It is an Observer.

Main.java creates objects, connects them together, and runs the program.

[pic]

1. Draw a sequence diagram of what happens when the main method is executed. Only the Main, Calculator, Display, and Console classes are required.

2. Run Main and enter some calculations (use multiple lines). Nothing is shown on the Display. Modify Main to make Display an observer of Calculator and run again.

Task 2: Create Command Objects for Operators

When the user presses "=" the calculator looks at the saved value of operator and performs the operation (+, -, *, etc). In the simple Calculator class it is done like this:

public void equalKeyPressed( ) {

if ( operator == '+' ) {

// add current register and save register, reset operator

setCurrentValue( getSaveValue() + getCurrentValue() );

setSaveValue(0);

operator = ' ';

}

if ( operation == '-' ) { /* perform subtraction */ }

...

We will eliminate the "if" statements by defining objects that know how to perform each operation. First, we define a simple interface for an operation:

Command Pattern:

The purpose of the Command Pattern is to encapsulate actions so that we can have a family of interchangeable actions, like "add", "subtract", "multiply". The object that invokes the action doesn't need to know which action he is invoking.

In this case, the Calculator can perform any operation by executing:

operator.perform( this );

We want to modify the enterKeyPressed( ) method of Calculator so it works like this:

public void equalKeyPressed( ) {

operator.perform( ); // no "if" !!

operator = null; // done this operator

}

1. Create AddOperator and SubtractOperator classes that implements Operator and performs + and - of calculator values. You can cut/paste code from the equalKeyPressed method of Calculator:

package calculator;

/** addition operation */

public class AddOperator implements Operator {

@Override

public void perform(Calculator calculator) {

long result = calculator.getCurrentValue() + calculator.getSaveValue();

calculator.setCurrentValue(result);

}

public String toString() { return "+"; } // so we can "print" the operator

}

2. Modify the Console class so that it creates objects for "add" and "subtract" and send these objects to the Calculator. Here is partial code:

private Operator add = new AddOperator();

private Operator subtract = new SubtractOperator();

public void acceptInput( ) throws IOException {

int c = 0;

while( ((c=System.in.read())) > 0 ) {

char ch = (char)c;

if ( ch == '+' ) calculator.operatorKeyPressed(add);

if ( ch == '-' ) calculator.operatorKeyPressed(subtract);

3. Modify the Calculator operatorKeyPressed so that the parameter is an Operator instead of char.

4. Test the calculator.

Task 3: Create a "State" model of Calculator and Implement Strategies

The Simple Calculator doesn't behave like a real calculator.

For example, try entering this sequence on the simple calculator and a real calculator:

4

+

20

-

10

=

*

5

See the difference? Can you think of other inputs where the behavior is different?

To make the calculator behave more like a real calculator, it needs to remember its state.

We will create 2 states (you can choose your own names):

START_NEW_VALUE - next digit key pressed start a new current value

APPEND_TO_VALUE - next digit key pressed is appended to current value

The calculator reacts differently to key press events in these two states.

1. What methods need to know about state?

2. Draw a State Chart diagram showing the states and transitions between states.

We could handle state by adding a "state" variable and conditional logic like:

if (state == START_NEW_VALUE ) ...

else ....

but we make a simpler, more flexible calculator using the Strategy pattern (or State pattern).

3. Implement classes for KeyPressStrategy to cause the calculator to behave differently depending on which state it is in.

4. In the Calculator class, the numberKeyPressed() and operatorKeyPressed() methods should invoke a Strategy to perform the action. Here is a partial code (it will be explained in the lab):

private KeyEventStrategy strategy;

/**

* Handle operator key press.

* @param operator is an operator of the calculator

*/

public void operatorKeyPressed( Operator operator ) {

strategy.operatorKeyPressed(operator);

}

5. The calculator needs a way to set the current strategy (that is, to set the state) so we should define a setStrategy method. Since the intent of this method is to change the state of the calculator, you may want to name it setState( ) instead:

public void setStrategy( KeyEventStrategy strategy ) {

this.strategy = strategy;

}

With some work, you can implement strategies so that no "if" statements are needed in the behavior of the calculator.

You should use a State Chart diagram and executable table (as on page 1) to help you determine how to implement the methods for each KeyEventStrategy.

Task 4: Use Actions to Encapsulate Behavior in the UI (Command Pattern)

Java has an Action interface and an AbstractAction class you can use to define Actions. For example, to define an "Action" for entering a '1' digit on the calculator we could do this:

// create Action object

Action oneKeyAction = new KeyAction( '1' );

// create a JButton and assign action to it

JButton button = new JButton( oneKeyAction );

class KeyAction extends AbstractAction {

private char key;

public KeyAction( char key ) {

super(Character.toString(key));

public void actionPerformed(ActionEvent e) {

calculator.digitKeyPressed(key);

}

}

The JButton gets its name from the KeyAction and uses the Action to handle events.

In the lab, we will see how to encapsulate all the button behavior and create a keypad for the calculator.

-----------------------

Operator

+perform( Calculator ): void

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download