|
Comp201: Principles of Object-Oriented Programming I
|
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.
This lab, in all its parts, comprises the homework assignment for this week. You are to start the work during lab and continue it on your own to be handed in next week.
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 '+', 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.
You may download the partially completed GUI code here: AFrame.java & InfixGUI.java (put them in a package called "infixView")
Warning! As you progress through the lab, the directions will deliberately get less and less detailed, as you are expected to figure more and more of the process out on your own!
This lab constitutes the homework for this week.
Study the above state transition diagram!
Get the downloaded GUI files to compile and run.
- Create stub class files for InfixCalc, ACalcState, IBinOp, AddOp and MulOp as shown in the UML class diagram; be sure to put it in the infixModel subdirectory (package).
- Make AddOp and MulOp singletons and write the code for their compute() methods. This should be trivial.
- Look at the javadoc/UML documentation of the ErrorState field in ACalcState. It is set to a "do-nothing" state. This is called the "Null Object Pattern". Copy the code for ErrorState to your ACalcState file.
- Add appropriate System.out.println statements to the public methods of InfixCalc, AddOp and MulOp.
- Compile and run; click all the buttons to prove that your listeners are really listening.
- Create concrete classes StartState, AccumState, PointState and CompState as shown in the javadoc/UML diagram.
- Be sure to make them singletons.
- Add appropriate System.out.println statements to their public methods.
- Now, go back to InfixCalc and apply the state pattern by delegating all state-dependent behaviors to the state. Is clear() a state-dependent behavior?
- Compile and run to see that the delegations are made.
- 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.
- Compile and manually test each of the classes by testing each of the click events.
- 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 Thursday, 03-Jun-2010 09:50:13 CDT
©2006 Stephen Wong and Dung Nguyen