| CS 535: Object-Oriented Programming & Design |
|
|---|
Fall Semester, 1997
Doc 24, Missing Responsibilities and Menus
To Lecture Notes Index
San Diego State University -- This page last updated 24-Nov-97
Contents of Doc 24, Missing Responsibilities and Menus
- References
- Missing Classes Responsibilities
- Menu Class
- Menu Example with Counter
- Reducing the Intelligence of Main
- Callbacks for the Menu
- Now the Menu and Example Classes
- Sample Main Program
- MenuItem
- Menu
- Counter class
- ASCIICounterView
Java 1.1 JDK documentation
Basic Scenario for Room Assignment
User starts program
Program displays main menu
User selects schedule new one time event
Program requests required information for the event
etc.
Who does the work ?
Which class displays the menu?
Which class requests required information for the event?
Common Answer
class Driver
{
public static void main( String args[] )
{
System.out.println( "Welcome to Room Scheduler");
System.out.println( "-------------------------");
System.out.println( "Please select one of the following:");
System.out.println( "");
System.out.println( "1. Find an event");
System.out.println( "2. Schedule an event");
System.out.println( "3. Quit");
int request = Console.readInt( "Your Selection: " );
// etc
}
}
Improved Version
class Driver
{
public static void main( String args[] )
{
int userSelection = showMainMenu();
// etc
}
public static int showMainMenu()
{
Console.println( "Welcome to Room Scheduler");
Console.println( "-------------------------");
Console.println( "Please select one of the following:");
Console.println( "");
Console.println( "1. Find an event");
Console.println( "2. Schedule an event");
Console.println( "3. Quit");
int request = Console.readInt( "Your Selection: " );
while ( (request >3) || (request < 1 ))
{
Console.println( "Your selection must be 1, 2, 3");
request = Console.readInt( "Your Selection: " );
}
return request;
}
}
What is the Abstraction?
Where is the code reuse?
import java.util.Vector;
import sdsu.io.Console;
class Menu
{
Vector menuItems = new Vector();
String menuMessage;
public void add( String newMenuItem )
{
menuItems.addElement( newMenuItem );
}
public void remove( int menuItemIndex )
{
menuItems.removeElementAt( menuItemIndex );
}
public void setMessage( String message )
{
menuMessage = message;
}
private void displayMenuItems()
{
for ( int index = 1; index <= menuItems.size();index++)
{
Console.println( "" + index + ". " +
menuItems.elementAt( index - 1 ));
}
}
//Menu Class continued
public int show()
{
Console.println( menuMessage );
Console.println( );
displayMenuItems();
int request = Console.readInt( "Your Selection: " );
while ( (request > menuItems.size() ) || (request < 1 ))
{
Console.println(
"Your selection must be between 1 and " +
(menuItems.size() - 1) );
request = Console.readInt( "Your Selection: " );
}
return request;
}
}
See Doc 23 slide 9 for Counter code
class Test
{
public static void main( String args[] )
{
Menu counterMenu = new Menu();
counterMenu.add( "Increase Counter" );
counterMenu.add( "Decrease Counter" );
counterMenu.add( "Display Counter" );
counterMenu.add( "Quit" );
Counter testCount = new Counter();
int userSelection;
do
{
userSelection = counterMenu.show();
switch (userSelection)
{
case 1:
testCount.increase();
break;
case 2:
testCount.decrease();
break;
case 3:
Console.println( "Counter value = " + testCount);
break;
}
}
while ( userSelection != 4 );
}
}
The main program still is in control of the order of execution of the
program
In many systems menus are implemented using callbacks
Each menu item is provided with a function, the callback
The callback function is called by the menu when ever the menu item is
selected
Since Java does not have functions, need an object and method for a callback
Use java.lang.reflect classes to obtain an object-oriented callback
(Note: AWT does not use object-oriented callback it uses Listeners)
Object-oriented callbacks are slow in Java,
They are fine for user-interface components, but not other parts of code
I use object-oriented callbacks here just because I though they would take
fewer slides to illustrate
(But there is one mysterious slide)
Class java.lang.reflect.Method
This class acts like a reference to a method of a class
import java.lang.reflect.Method;
class Foo
{
public void bar()
{
System.out.println( "Hi Mom" );
}
}
class TestMethod
{
public static void main( String[] arg) throws Exception
{
Foo test = new Foo();
Class classOfTest = test.getClass();
Class[] classOfBarsParameters = new Class[0];
Method bar =
classOfTest.getMethod( "bar", classOfBarsParameters);
bar.invoke( test, new Class[0]);
}
}
MenuItem
Represents a individual item in a menu
public MenuItem( String menuText,
Object callBackObject,
String callBackMethod)
menuText - string shown on screen for this item in menu
callBackObject
callBackMethod
- String representation of method that will be sent the object callBackObject
when this menu item is selected by the user
Menu
Represents a menu
public void add( MenuItem newMenuItem )
- Adds a new menu item to the menu
public void show()
- Actives the menu, menu will prompt user for selections and perform selected
actions until user selects "Quit" or another object sends "hide" to the menu
Counter (extends Observable)
A simple counter that extend Observable
Main methods besides Observable methods:
- increase
-
- decrease
-
- reset
-
- toString()
ASCIICounterView (implements Observer)
Main method:
- update - prints out the current value of the counter that it
observes
class SampleMainProgram
{
public static void main( String args[] ) throws Exception
{
Counter count = new Counter();
count.addObserver( new ASCIICounterView( ) );
Menu counterMenu = new Menu();
// Note menu automatically adds a Quit Menu Item
counterMenu.add(
new MenuItem("Increase Counter", count, "increase" ));
counterMenu.add(
new MenuItem("Decrease Counter", count, "decrease" ));
counterMenu.add(
new MenuItem("Reset Counter", count, "reset" ));
counterMenu.show();
}
}
Sample Run of Program
---------------------------
1. Exit
2. Increase Counter
3. Decrease Counter
4. Reset Counter
Your Selection: 2
The current count is: 1
---------------------------
1. Exit
2. Increase Counter
3. Decrease Counter
4. Reset Counter
Your Selection: 2
The current count is: 2
---------------------------
1. Exit
2. Increase Counter
3. Decrease Counter
4. Reset Counter
Your Selection: 1
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
class MenuItem
{
String text;
Object callBackObject;
Method callBackMethod;
public MenuItem( String menuText,
Object callBackObject,
String callBackMethod)
throws NoSuchMethodException
{
text = menuText;
this.callBackObject = callBackObject;
Class callBackClass = callBackObject.getClass();
Class[] parameters = new Class[0];
this.callBackMethod = callBackClass.getMethod(
callBackMethod, parameters);
}
public String getText()
{
return text;
}
public String toString()
{
return text;
}
//MenuItem continued
public void invokeCallBack()
{
try
{
callBackMethod.invoke( callBackObject, new Class[0] );
}
catch ( IllegalAccessException violatedMethodProtection )
{
System.err.println( "MenuTime: " +
violatedMethodProtection );
}
catch ( InvocationTargetException callBackException )
{
System.err.println( "MenuTime: " + callBackException );
}
}
}
class Menu
{
Vector menuItems = new Vector();
boolean repeatMenu = true;
public Menu()
{
try
{
menuItems.addElement( "Null Object for 0'th index" );
menuItems.addElement(
new MenuItem("Exit", this, "hide"));
}
catch ( NoSuchMethodException canNotHappen)
{
System.err.println( "Exception in Menu: " +
canNotHappen);
}
}
public void add( MenuItem newMenuItem )
{
menuItems.addElement( newMenuItem );
}
public void hide()
{
repeatMenu = false;
}
// Menu Continued
public void show()
{
do
{
MenuItem selectedMenuItem =
getUsersMenuSelection();
selectedMenuItem.invokeCallBack();
}
while ( repeatMenu );
}
private MenuItem getUsersMenuSelection()
{
Console.println( "\n\n---------------------------");
int request = displayMenuItems();
while ( (request >= menuItems.size() ) || (request < 1 ))
{
Console.println( "Your selection must be between 1 and "
+ (menuItems.size() - 1));
request = displayMenuItems();
}
return (MenuItem) menuItems.elementAt( request);
}
private int displayMenuItems()
{
for ( int index = 1; index < menuItems.size();index++)
{
Console.println( "" + index + ". " +
menuItems.elementAt( index ));
}
return Console.readInt( "Your Selection: " );
}
}
class Counter extends Observable {
private int count = 0;
protected void changeNotify() {
setChanged();
notifyObservers( );
}
public void increase() {
count++;
changeNotify();
}
public void decrease() {
count--;
changeNotify();
}
public void reset() {
count = 0;
changeNotify();
}
public int value() {
return count;
}
public String toString() {
return String.valueOf( count );
}
}
class ASCIICounterView implements Observer
{
public void update( Observable sender, Object message )
{
System.out.println( "\nThe current count is: " +
((Counter) sender) );
}
}