In this lab we will create Graphical User Interface ("GUI") "Cheap Calculator" program which can do the four basic arithmetic operations: addition, subtraction, multiplication and division.
To see where we are going, download and run the demo As you can see this is a really cheap calculator: it misses a couple of digit buttons and does not support subtraction nor division. Nevertheless, it seems to calculate arithmetic expression in infix notation correctly. What do we mean by an "infix" expression? A binary operation is said to be in infix notation if the operator (e.g. +) is in between the two operands. There are also "postfix" and "prefix" expressions. The following table shows an example of each form of notation.
Adding two numbers x, y together
Infix Notation x + y Prefix Notation + x y Postfix Notation x y +
Note that it is an Honor Code violation to attempt to decompile the demo.
I am interested in writing a GUI application that simulates the behavior of a "cheap" infix calculator. As the user interface, this calculator has on the outside:
· 10 buttons labeled 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, respectively, to enter digit characters
· one button labeled . to enter the decimal point
· one button labeled +, to perform addition
· one button labeled *, to perform multiplication
· one button labeled =, to compute the result of the input so far
· one button labeled C, to clear all entries in the calculator and reset the calculator to its pristine initial state.
· and a display text field for me to view the input and the result of my desired computation.
Inside this calculator is perhaps some kind of electronic circuit board capable of carrying out the actual computations. The GUI provides the only way for me to interact with the internals of the calculator. How do I want the calculator to behave like? For a start, as I click on the digit buttons, I expect the calculator to accumulate the digits by concatenating them together and displaying the result on the display text field. But wait! What if I only click the digit '0' button? The calculator should not concatenate one '0' after another, should it? Run the demo and check it out yourself!
Now, try this: click '3', then click '0' four times. This time around, clicking '0' results consistently in concatenating '0' to the existing display text. The calculator has changed its "click '0'" behavior after I click a digit button that is not a '0'. We say that the calculator has gone through a "state change" and behaves differently in each state.
Here is another of example.
First click C to reset the calculator. The display should show '0'.
Now, click '3', then '3' again, then '3' again.
What do you see? The first time you click '3', the calculator replaces '0' with '3'. Then for each subsequent click on '3', the calculator simply appends '3' to the current display text field and update it with the resulting string. You should see "333" at this point.
Next, click '+': "333" is still being display. But now click '3'. What happens? '3' is no longer appended to the existing display string, isn't it? You are sending the same message to the calculator by clicking the same '3', but the calculator responds differently this time, doesn't it? It has dynamically changed its behavior after you clicked on '+'! Again what we see here is another example of "state change". Clicking the '+' causes the calculator to transition to another state.
The behaviors of my calculator can be modeled as what is called a "finite state machine." What is a state? How many states are there? How do we go about describing the behavior of the calculator as it changes from state to state?
When you click on a button of the calculator, you are in effect making a request to the calculator to perform certain task. At any point in time, the internals of the calculator are in some specific conditions with specific values that would cause the calculator to respond in a very specific manner to such a request. The condition in which the calculator is in at any point in time is called the state of the calculator at that point in time. A state of a system is defined by the behaviors of the system. The user can interact with the calculator in only five ways:
To specify the behavior of the calculator, we must specify the calculator's response to each of the above five clicking events.
When you first turn on the calculator, imagine that it is in some initial condition called a start state. Suppose, from the start state, you...
Beginning with one state, the start state, by analyzing and specifying the behavior of the calculator in response to the five distinct click events, we have inferred the existence of four distinct other states: accumulate state, compute state, point state and error state. We can repeat the same analysis on each of these states for each of the click events. We will not discussed them in details here. Instead, we summarize the state behaviors and the state transition in the form of a diagram shown below.
Traditional procedural programming implements the behavior of finite state machines by using numbers, loops and conditional constructs such as if and switch statements. In OOP, each state is an object with behaviors. A finite state machine is an object that has states. The machine holds a reference to an abstract state and delegates all state-dependent behaviors to its current state. This is the gist of what is called the state design pattern. We will apply the state pattern to model the cheap calculator. Here is the UML diagram of the complete system that we will be building:
The documentation for the above classes can viewed here.
Study the above state transition diagram!
Download and unzip the stub code for the above design.
Study the code for InfixCalc to see how all state-dependent behaviors are delegated to the current state.
NOTE: For the sake of expediency, we are "hardwiring" the model (InfixCalc) to its view (InfixGUI), instead of using adapters and a controller to connect the model and the view as usually done. We encourage that you modify the above design to make it a true MVC design.
The stub code should compile. The main class is demo.AppLauncher.java. You should be able to run AppLauncher. However the calculator does not work as specified.
- Imitate the code for StartState to complete the code for AccumState, PointState and CompState: use the above state diagram to write the code for all the methods of each of the concrete state classes, one class at a time.
- Your code should compile and run like the demo applet.
- Modify InFixGUI to add a '1' button and a '2' button. Add appropriate event listeners for these two buttons.
- Add a subtraction binary operation and a division binary operation.
- Modify InFixGUI to add a subtraction button and a division button. Add appropriate event listeners for these two buttons.
- Compile and run and test at each of the above steps.
- You now should have a fully functional "cheap" calculator.
Last Revised Monday, 07-Apr-2008 11:48:58 CDT
©2008 Stephen Wong and Dung Nguyen