INTRODUCTION TO PRPGRAMMING IN JAVA: SELECTION (MENUS)

NOTE: This set of www pages is not the set of www pages for the curent version of COMP101. The pages are from a previous version that, at the request of students, I have kept on line.


CONTENTS

1. Introduction
2. Example problem - Temperature conversion
2.1. Requirements
2.2. Analysis
 
2.3. Design
2.4. Implementation
2.5. Testing

The example problem, other than giving a practical illustration of a menu interface, also serves as a revision of the Java inheritance mechanism and the use of the round method found in the Math class.




1. INTRODUCTION

A common "interface" requirement is to allow a user to select from a number of alternatives. A simple way of doing this is to present the user with a list of possibilities from which to choose from (this type of interface is less error prone). In sophisticated "window" interfaces the selection is made through mouse clicks. An alternative and simpler interface is to allow the user to indicate a selection by entering a number or letter at the keyboard. The disadvantage associated with this simpler approach is that the user may make erroneous inputs and therefore the interface must include some error recovery mechanism.

 

Consider the Java application program given in Table 1. Note that it comprises a "top level" main method and two other methods, outputMenu and processSelector. The first outputs a list of options (i.e. a menu not unlike a restaurant menu) from which the user can make a single selection by entering the appropriate number associated with the desired option. The selection is then processed by the processSelector method which includes an error recovery mechanism which will cause the program to repeat until a valid option is entered. Some example output is presented in Table 2 and an Activity Diagram for the code in Figure 1.

// MENU INTERFACE EXAMPLE APPLICATION
// Frans Coenen
// Thursday 15 April 1999
// Revised: Tuesday 26 July 2005
// The University of Liverpool, UK   

import java.util.*;

class MenuInterfaceExApp {

    // ------------------- FIELDS ------------------------ 
        
    // Create Scanner class instance

    private static Scanner input = new Scanner(System.in);
    
    // ------------------ METHODS ------------------------  
    
    /* Main method */
    
    public static void main(String[] args) {
        // Output menu
        int selector = outputMenu();

        // Process selection
        processSelector(selector);
        }

    /* Output menu */

    private static int outputMenu() {
        System.out.println("PROGRAMMING PARADIGMS");
	System.out.println("=====================");
	System.out.println("1. Imperative");
	System.out.println("2. Object oriented");
	System.out.println("3. Logic");
	System.out.println("4. Functional");
	System.out.println("Select option: ");
	    
	// Return
	return(input.nextInt());    
	}

    /* Process selector. If unrecognised selection output error message and 
    repeat. */
	
    private static void processSelector(int selector) {	
	switch (selector) {
	    case 1:
	        System.out.println("Example languages include C, Ada and " +
			"Pascal");
		break;
	    case 2:
	        System.out.println("Example languages include Java, Eiffel " +
			" and C++");
		break;
	    case 3:
                System.out.println("Example languages include Prolog");
		break;
	    case 4:
                System.out.println("Example languages include Lisp and " +
			" Miranda");
		break;
            default:
                System.out.println("ERROR: Unrecognised menu selection " +
			selector + "!");
		selector = outputMenu();
		processSelector(selector);
	    }
        }
    }

Table 1: Example Java application program illustrating menu interface

MENU EXAMPLE ACTIVITY DIAGRAM

Figure 1: Activity diagram for code presented in Table 1

$ java MenuInterfaceExApp
PROGRAMMING PARADIGMS
=====================
1. Imperative
2. Object oriented
3. Logic
4. Functional
Select option:
5
ERROR: Unrecognised menu selection 5!
PROGRAMMING PARADIGMS
=====================
1. Imperative
2. Object oriented
3. Logic
4. Functional
Select option:
2
Example languages include Java, Eiffel and C++        

Table 2: Example output from application program given in Table 1



2. EXAMPLE PROBLEM TEMPERATURE CONVERSION


2.1 Requirements

Design and implement a Java program the takes as input a temperature presented in degrees Centigrade, Fahrenheit, Kelvin or Reaumur and converts it to an equivalent temperature in degrees Centigrade, Fahrenheit, Kelvin or Reaumur. The following identities might be useful:

C = (F-32) x 9/5    C = K-273    C = R x 8/10
F = (C x 9/5) + 32   F = ((K-273) x 9/5) + 32   F = (R x 36/25) + 32
K = C + 273    K = ((F-32) x 9/5) + 273   K = (R x 8/10) + 273
R = C x 10/8    R = (F-32) x 36/25    R = (K-273) x 10/8
THERMOMETER DIAGRAM

2.2 Analysis

There are a number of design considerations here:

  1. How do we allow the user to input the required conversion?
  2. Do we need conversion routines for every possibility? There are currently 12 (4x3) possibilities, but with an eye to future maintenance if a further scale is included this will go up to 20 (5x4). In fact the number of options is given by the identity n^2xn (where n is the number of different temperature scales to be considered).

To address the first we will adopt a menu interface where the user selects from a number of alternatives which are then acted upon (see above). We will include an error recovery mechanism to be invoked should the user enter an option which is not recognised by the program.

To address the second we will reduce the number of conversion methods required by always converting the temperature of the input scale into centigrade and then convert this into the desired output scale. Given that one of the input/output options is already in Centigrade this means we will require only 6 conversion methods ((n-1)+(n-1)), a greatly reduced number. A schematic outlining this approach is given in Figure 2.

TEMPERATURE CONVERSION SCHEMATIC

Figure 2: Temperature conversion schematic

In the light of the above a class hierarchy of the form given in Figure 3 is suggested. Here we have a super-class temperature, which has four sub-classes descending from it --- Centigrade, Fahrenheit, Kelvin and Reaumur. We also have an application class temperatureConversion.

TEMPERATURE CONVERSION CLASS DIAGRAM

Figure 3: Temperature conversion class diagram


2.3 Design


2.3.1 Temperature Class


Field Summary
protected int temperature
           An instance variable to store "b" value of an instance of the class LinearEquation.

Constructor Summary
Temperature(int newTemperature)
           Constructor creates an instance of the class Temperature given an integer temperature value (newTemperature) for that instance.

Method Summary
public int getTemperature()
           Public method to return the protected temperature variable of an instance of the class Temperature. No arguments.

2.3.2 Centigrade Class


Constructor Summary
Centigrade(int newTemperature)
           Constructor creates an instance of the class Centigrade given a temperature as its formal parameter. (Also invokes constructor for the temperature super class.)

Method Summary
public int cent2fahr()
           Public method to convert a Centigrade temperature to a Fahrenheit temperature and return the result. Uses the round method in the Math class to convert from a float to an int.
public int cent2kelv()
           Public method to convert a Centigrade temperature to a Kelvin temperature and return the result and return the result. Uses the round method in the Math class to convert from a float to an int.
public int cent2reau<)
           Public method to convert a Centigrade temperature to a Reaumur temperature and return the result and return the result. Uses the round method in the Math class to convert from a float to an int.

2.3.3 Fahrenheit Class


Constructor Summary
Fahrenheit(int newTemperature)
           Constructor creates an instance of the class Fahrenheit given a temperature as its formal parameter. (Also invokes constructor for the temperature super class.)

Method Summary
public int fahr2cent()
           Public method to convert a Fahrenheit temperature to a Centigrade temperature and return the result.

2.3.4 Kelvin Class


Constructor Summary
Kelvin(int newTemperature)
           Constructor creates an instance of the class Kelvin given a temperature as its formal parameter. (Also invokes constructor for the temperature super class.)

Method Summary
public int kelv2cent()
           Public method to convert a Kelvin temperature to a Centigrade temperature and return the result.

2.3.5 Reaumur Class


Constructor Summary
Reaumur(int newTemperature)
           Constructor creates an instance of the class Reaumur given a temperature as its formal parameter. (Also invokes constructor for the temperature super class.)

Method Summary
public int reau2cent()
           Public method to convert a Reaumur temperature to a Centigrade temperature and return the result.

Although the above constructors and methods are all straight forward we should still include appropriate Nassi-Shneiderman charts for each as shown in Figure 4.

NASSI-SHNEIDERMAN CHART FOR TEMPERATURE CLASSES

Figure 4: Nassi-Shneiderman charts for Temperature class and its sub-classes


2.3.6 TempConvertApp Classes

Field Summary
private static Scanner input
           A class instance to facilitate input from the input stream.

Method Summary
public static void main(String[] args)
           Top level method for temperature conversion application. Calls the inputFromCode class method.
private static void inputFromCode()
           Class method to allow user to input temperature scale (C, F, K or R) from which to convert "from". Includes an input error checking mechanism. If an error is found an appropriate error message will be displayed and the user will be presented with another opportunity to input a "from" scale identifier. Checking mechanism will be implemented using a switch statement. If successful method makes a call to the inputToCode method.
private static void inputToCode(char fromCode)
           Class method to allow user to input temperature scale (C, F, K or R) from which to convert "to". Includes an input error checking mechanism to check that:

  1. To code is a recognised identifier (C, F, K or R).
  2. To and from codes are different.

If an error is found an appropriate error message will be displayed and the user will be presented with another opportunity to input a "to" scale identifier. Checking mechanism will be implemented using a switch statement. If successful method makes a call to the inputFromTemp method.

private static void inputFromTemp(char fromCode, char toCode)
           Class method to allow user to input an appropriate temperature on the "from" scale. Given this temperature an instance of the appropriate "from" temperature class is created. Which is then converted, if necessary, to be an instance of the class Centigrade. On completion the tempConversion method is called to carry out the required calculation. Again use is made of a switch statement to carry out the necessary conversion.
private static void tempConversion(Centigrade centTemp, char toCode)
           Class method to carry out required conversion. If "to" code is C no further conversion will be required. Otherwise a new temperature must be generated and this then used to create an instance of the appropriate class. On completion the final result is output to the user (using a call to the getTemperature method in the Temperature class).
private static void finalOutput(Centigrade centTemp, char toCode)
           Class method to output the final result. A separate method is used for this end designed to operate with any instance of the class temperature or a sub-class of this class.

A set of Nassi-Shneiderman charts for the above methods are presented in Figure 5. A set of Activity Diagrams for the entire system is given in Figure 6; Figure 6(a) gives a high level view while figures 6(b), (c) and (d) give more detailed views of the flow of control through the system. The procedure for input of both the "from" and "to" code, with respect to flow of control, is identical and is therefore presented in the form of a single Activity Diagram (Figure 6(b)).


NASSI-SHNEIDERMAN CHART FOR TEMPERATURE CONVERSION APPLICATION
	CLASS 1 NASSI-SHNEIDERMAN CHART FOR TEMPERATURE CONVERSION APPLICATION
	CLASS 2

Figure 5: Nassi-Shneiderman charts for TempConvertApp class

HIGH LEVEL ACTIVITY DIAGRAM FOR TEMPERATURE CONVERSION APPLICATION

(a) High level view of flow of control

INPUT FROM VALUE ACTIVITY DIAGRAM FOR TEMPERATURE CONVERSION APPLICATION

(c) Input from value procedure

INPUT TO/FROM CODES ACTIVITY DIAGRAM FOR TEMPERATURE CONVERSION APPLICATION

(b) Input from/to code procedure

CONVERSION ACTIVITY DIAGRAM FOR TEMPERATURE CONVERSION APPLICATION

(d) Conversion procedure

Figure 6: Activity diagram for temperature conversion application


2.4. Implementation


2.4.1 Temperature class (and associated sub-classes)

// TEMPERATURE CONVERSION
// Frans Coenen
// Sunday 26 March 1999
// The University of Liverpool, UK

/********************************************/
/*                                          */
/*               TEMPERATURE                */
/*                                          */
/********************************************/

class Temperature {

    // ------------------ FIELDS ----------------------

    protected int temperature;
    
    // ----------------- CONSTRUCTORS -----------------
    
    /* Temperature constructor */
    
    public Temperature(int newTemperature) {
    	temperature = newTemperature;
	}
	
    // ------------------ METHODS ---------------------
    
    /* Get temperature */
    
    public int getTemperature() {
        return(temperature);
	}
    }    
    
/*******************************************/
/*                                         */
/*               CENTIGRADE                */
/*                                         */
/*******************************************/    
    
class Centigrade extends Temperature{
    
    // ----------------- CONSTRUCTORS -----------------
    
    /* Centigrade constructor */
    
    public Centigrade(int newTemperature) {
    	super(newTemperature);
	}
	
    // -------------------- METHODS -------------------
    
    /* Centigrade to Fahrenheit conversion */
    
    public int cent2fahr() {
    	return((9*temperature/5)+32);
    	}	
	
    /* Centigrade to Kelvin conversion */
    
    public int cent2kelv() {
    	return(temperature+273);
    	}
		
    /* Centigrade to Reaumur conversion */
    
    public int cent2reau() {
    	return(8*temperature/10);
    	}		
    }   
    
/*******************************************/
/*                                         */
/*               FAHRENHEIT                */
/*                                         */
/*******************************************/

class Fahrenheit extends Temperature{
    
    // ----------------- CONSTRUCTORS -----------------
    
    /* Fahrenheit constructor */
    
    public Fahrenheit(int newTemperature) {
    	super(newTemperature);
	}
	
    // -------------------- METHODS -------------------
    
    /* Fahrenheit to Centigrade conversion */
    
    public int fahr2cent() {
    	return((temperature-32)*5/9);
    	}			
    }   

/***************************************/
/*                                     */
/*               KELVIN                */
/*                                     */
/***************************************/

class Kelvin extends Temperature{

    // ----------------- CONSTRUCTORS -----------------
    
    /* Kelvin constructor */
    
    public Kelvin(int newTemperature) {
    	super(newTemperature);
	}
	
    // -------------------- METHODS -------------------
    
    /* Kelvin to Centigrade conversion */
    
    public int kelv2cent() {
    	return(temperature-273);
    	}			
    }   
    
/***************************************/
/*                                     */
/*               REAUMUR               */
/*                                     */
/***************************************/

class Reaumur extends Temperature{

    // ----------------- CONSTRUCTORS -----------------
    
    /* Reaumur constructor */
    
    public Reaumur(int newTemperature) {
    	super(newTemperature);
	}
	
    // -------------------- METHODS -------------------
    
    /* Reaumur to Centigrade conversion */
    
    public int reau2cent() {
    	return(temperature*10/8);
    	}			
    }   

Table 3: Temperature class hierarchy implementation


2.4.2 Temperature conversion application

// TEMPERATURE CONVERSION APPLICATION
// Frans Coenen
// Tuesday 30 March 1999
// Revise: Tuesday 26 July 2005
// The University of Liverpool, UK   

import java.util.*;

class TempConvertApp {
  
    // ------------------- FIELDS ------------------------ 
                      
    // Create Scanner class instance

    private static Scanner input = new Scanner(System.in);
                  
    // ------------------ METHODS ------------------------ 
    
    /* Main method to initiate processing. */
    
    public static void main(String[] args) {
        inputFromCode();
	}
    
    /* Input From Code. Method to allow input of "from code". 
    If an unrecognised code is entered then the method calls 
    itself again (recurs). */
    
    private static void inputFromCode() {
	
        // Input from code
	
    	System.out.println("Temperature Conversion");
    	System.out.println("======================");
	System.out.print("Enter Conversion From Code (67 = Centigrade,\n\t" +
			   "70 = Fahrenheit, 75 = Kelvin, 82 = Reamur): ");
	char fromCode = (char) input.nextInt();
	
	// Check from Code
	
	switch (fromCode) {
	    case 'C':
	    case 'F':
	    case 'K':
	    case 'R':
	        inputToCode(fromCode);
		break;
	    default:
	        System.out.println("ERROR 1: Unrecognised from code " +
				" (67 = Centigrade,\n\t70 = Fahrenheit," + 
				" 75 = Kelvin, 82 = Reamur) --- " + 
				((int) fromCode));
		inputFromCode(); 	
	    }
	}
	
    /* Input To Code. Method to allow input of "to code". If an 
    unrecognised code is entered then the method calls itself again 
    (recurs). Method also checks if user is asking to convert a 
    temperature to a temperature on the same scale (i.e. the from and 
    to codes are identical. */
	
    private  static void inputToCode(char fromCode) {
	
	// Input to code 
	      
	System.out.print("Enter Conversion To Code (67 = Centigrade,\n\t" +
			 "70 = Fahrenheit, 75 = Kelvin, 82 = Reamur): ");
	char toCode = (char) input.nextInt();
	
	// Check from Code
	
	switch (toCode) {
	    case 'C':
	    case 'F':
	    case 'K':
	    case 'R':
	    	if (fromCode == toCode) {
		    System.out.println("ERROR 2: From and to codes are " +
		    	"identical (" + fromCode + " == " + toCode + ")");
		    inputToCode(fromCode);	
		    }
	        else inputFromTemp(fromCode,toCode);
		break;
	    default:
	        System.out.println("ERROR 3: Unrecognised to code " +
				" (67 = Centigrade,\n\t70 = Fahrenheit," + 
				" 75 = Kelvin, 82 = Reamur) --- " + 
				((int) toCode));
		inputToCode(fromCode); 	
	    }	
	}
	
    /* Input from temperature. Method to allow input of from temperature. */
    
    private  static void inputFromTemp(char fromCode, char toCode) {
	Centigrade centFromTemp;
	
        // Input temperature
	
	System.out.print("Enter " + fromCode + " temperature: ");
	int temperature = input.nextInt();
	
	// Create Instance of the appropriate class.
		
	switch(fromCode) {
	    case 'C':
		centFromTemp = new Centigrade(temperature);
	        break;			
	    case 'F':
	    	Fahrenheit fahrFromTemp = new Fahrenheit(temperature);
		centFromTemp            = new 
					Centigrade(fahrFromTemp.fahr2cent());
	        break;	
	    case 'K':
	    	Kelvin kelvFromTemp = new Kelvin(temperature);
	        centFromTemp        = new 
					Centigrade(kelvFromTemp.kelv2cent());
	        break;	
	    case 'R':
	    	Reaumur reauFromTemp = new Reaumur(temperature);
	        centFromTemp         = new 
					Centigrade(reauFromTemp.reau2cent());
	        break;		
	    default:
		System.out.println("ERROR 4: Coding error");
		return;
	    }
		
	// Instigate conversion
	
	tempConversion(centFromTemp,toCode);
	}
	
    /* Temperature conversion. Method to carry out the final 
    conversion and output the result. */
	
    private  static void tempConversion(Centigrade centTemp, char toCode) {
	
	// Convert
	
	switch(toCode) {
	    case 'C':
	    	finalOutput(centTemp,toCode);
	        break;			
	    case 'F':
	        Fahrenheit fahrTemp = new Fahrenheit(centTemp.cent2fahr());
		finalOutput(fahrTemp,toCode);
	        break;	
	    case 'K':
                Kelvin kelvTemp = new Kelvin(centTemp.cent2kelv());
		finalOutput(kelvTemp,toCode);
	        break;	
	    case 'R':
	        Reaumur reauTemp = new Reaumur(centTemp.cent2reau());
		finalOutput(reauTemp,toCode);
	        break;		
	    default:
		System.out.println("ERROR 5: Coding error");	
	    }		

        }	

    /* Final output */
    
    private  static void finalOutput(Temperature temp, char toCode) {
    	System.out.println("Equivalent " + toCode + " temperature is " + 
					temp.getTemperature() + " degrees");
	}
    }

Table 4: Temperature conversion application class

Notes:

The first formal parameter for the finalOutput method must be of type Temperature. However, inspection of the tempConversion method indicates that this is called with instance of type Centigrade, Fahrenheit, Kelvin and Reaumur! We can do this because all four are sub-classes of the class Temperature.

2.5. Testing

1. Path testing: From Figure 5 we can identify a number of paths through the system. Test cases to exercise each of these paths should be designed and used. A suitable set of cases is given in Table 5.

TEST CASEEXPECTED RESULT
FromToTemp.OUTPUT
A**Error
CA*Error
CC*Error
CF032
CK0273
CR00
FC0-17
FK0256
TEST CASEEXPECTED RESULT
FromToTemp.OUTPUT
FR0-13
KC0-273
KF0-459
KR0-218
RC00
RF032
RK0273

Table 5: Path testing test cases


2. Arithmetic testing: We should also carry out some arithmetic testing where we test zero negative and positive inputs. In table 5 we have already included a set of test cases where the input is zero. Further test cases, for negative and positive inputs, are given in Table 6. Note that in the table we have not include negative temperatures for the Kelvin scale because, in theory, no such temperatures can exist. Note also that when running these test cases there may be some variance between the predicted result and the actual results, especially when using high magnitude inputs because of the "rounding" that takes place when using integer division.

TEST CASEEXPECTED RESULT
FromToTemp.OUTPUT
CF100212
CK100373
CR10080
FC212100
FK212373
FR21280
KC373100
KF373212
KR37380
RC80100
RF80212
RK80373
TEST CASEEXPECTED RESULT
FromToTemp.OUTPUT
CF-273-459
CK-2730
CR-273-218
FC-459-273
FK-4590
FR-459-218
RC-218-273
RF-218-459
RK-2180

Table 6: Arithmetic testing test cases

An example run is givenm below:

$ java TempConvertApp
Temperature Conversion
======================
Enter Conversion From Code (67 = Centigrade,
        70 = Fahrenheit, 75 = Kelvin, 82 = Reamur): 70
Enter Conversion To Code (67 = Centigrade,
        70 = Fahrenheit, 75 = Kelvin, 82 = Reamur): 67
Enter F temperature: 4
Equivalent C temperature is -15 degrees



Created and maintained by Frans Coenen. Last updated 10 February 2015