The irresistable source.

Lab 2

Description: This is a program to simulate and record temperature data, as in lab 1, but with the following design improvements:

1. Improved delegation of responsibility with the introduction of a TextUI class that handles all user interaction. This allows the TemperatureSensorApp class to focus exclusively on program flow.

2. Improved MenuOption enum which directly relates the enum value to their integer counterparts on the user interface, for better readability.

Code:

package jwarren.lab2;
import jwarren.lab1.Temperature;
import jwarren.lab1.TemperatureRecord;
import jwarren.lab1.TemperatureSimulator;

//
//A temperature sensor simulation app.
//
public class TemperatureSensorApp {

	private static enum MenuOption{
		WINTER(1), SPRING(2), SUMMER(3), FALL(4), EXIT(5);

		private final int value;

		MenuOption(int n){

			value = n;
		}

		@SuppressWarnings("unused")
		public int getValue(){

			return value;
		}

		public static MenuOption fromValue(int v){

			MenuOption option;

			switch(v){

			case 1:
				option = MenuOption.WINTER;
				break;
			case 2:
				option = MenuOption.SPRING;
				break;
			case 3:
				option = MenuOption.SUMMER;
				break;
			case 4:
				option = MenuOption.FALL;
				break;
			case 5:
				option = MenuOption.EXIT;
				break;
			default:
				option = null;
			}

			return option;
		}

	}

	public static void main(String args[]){

		boolean done = false;
		int userInput;
		int numSimulations = 0;
		MenuOption selection = MenuOption.EXIT;
		TemperatureRecord record;
		TemperatureSimulator tempSim = new TemperatureSimulator();
		TextUI ui = new TextUI(System.in, System.out);

		//Display the welcome message.
		ui.print("Welcome to Season Sim®\n");

		do{
			//Display menu to user and get input
			try{
				ui.print("Select one of the following simulations:\n");
				ui.print(" for Winter simulation.\n");
				ui.print(" for Spring simulation.\n");
				ui.print(" for Summer simulation.\n");
				ui.print(" for Fall simulation.\n");
				ui.print("or  to exit the program.\n");
				ui.print(": ");
				userInput = ui.readInt(1,5);

				//Selection will be null if userInput is not valid enum value.
				selection = MenuOption.fromValue(userInput);

				//This should not happen unless TextUI is broken.
				if(selection == null){

					//Exit
					done = true;
				}

				else if(selection != MenuOption.EXIT){

					//Ask how man simulations to run.
					ui.print("Enter the number of simulations to run: ");
					numSimulations = ui.readInt(0,Integer.MAX_VALUE);

					record = runSimulations(numSimulations, selection, tempSim);

					//Display Temperature Statistics to user.
					ui.print("Statistics for " + selection + " season:\n");
					ui.print("First temp: " + record.getFirst() + "\n");
					ui.print("Last temp: " + record.getLast() + "\n");
					ui.print("Highest temp: " + record.getHighest() + "\n");
					ui.print("Lowest temp: " + record.getLowest() + "\n");
					ui.print("Sum: " + record.getSum() + "\n");
					ui.print("Average temp: " + record.getAvg() + "\n");
				}

				else{
					ui.print("Goodbye.\n");
					done = true;
				}
			}

			catch(TextUI.TextUIException e){
				ui.print(e.getMessage() + "\n");
				ui.print("Please try again...\n\n");
				done = false;
			}

		}while(!done);

	}

	//
	//Runs a specified number of Temperature simulations and returns a record of the runs.
	//
	private static TemperatureRecord runSimulations(int numSims, MenuOption selection, 
			TemperatureSimulator tempSim){

		double temp = 0;
		TemperatureRecord record = new TemperatureRecord();

		for(int i=0; i<numSims; i++){

			switch(selection){

			case WINTER:
				temp = tempSim.getWinterTemp();
				break;
			case SPRING:
				temp = tempSim.getSpringTemp();
				break;
			case SUMMER:
				temp = tempSim.getSummerTemp();
				break;
			case FALL:
				temp = tempSim.getFallTemp();
				break;
			case EXIT:
				System.err.println("Invalid option \'EXIT\' for simulation.");
				break;
			default:
				System.err.println("Unrecognized option for simulation.");
			}

			if(selection != MenuOption.EXIT){
				record.add(new Temperature(temp,Temperature.Units.FAHRENHEIT));
			}
		}

		return record;

	}

}

package jwarren.lab2;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.InputMismatchException;
import java.util.Scanner;

public class TextUI {

	private Scanner in;
	private PrintStream out;

	//
	//Exception super type thrown by this class.
	//
	public static class TextUIException extends Exception{

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		TextUIException(String msg){
			super(msg);
		}

	}

	//
	//Exception thrown when UI encounters an invalid input.
	//
	public static class InvalidInputException extends TextUIException{

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		InvalidInputException(String msg){

			super(msg);
		}

	}

	//
	//Exception thrown when a non computable range is encountered
	//
	public static class InvalidInputRangeException extends TextUIException{

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		InvalidInputRangeException(String msg){

			super(msg);
		}
	}

	//
	//Initialization Constructor.
	//
	public TextUI(InputStream iStream, OutputStream oStream){

		in = new Scanner(iStream);
		out = new PrintStream(oStream);
	}

	//
	//Prints to the output stream.
	//
	public void print(String msg){

		out.print(msg);
	}

	//
	//Reads an integer from the output stream. This method will return a value between
	//min - max (inclusive) or thrown an InvalidInputException.
	//
	public int readInt(int min, int max) throws TextUIException{

		int input = 0;

		if(max < min){

			throw new InvalidInputRangeException("Max value cannot be set below minimum.");
		}

		try{

			input = in.nextInt();
		}

		catch(InputMismatchException e){

			in.next();
			throw new InvalidInputException("Must enter an integer.");
		}

		if(input < min || input > max){

			throw new InvalidInputException("\""+input+"\" is not within valid "
					+ "range: " + min + " through " + max + ".");
		}

		return input;
	}
}

package jwarren.lab1;
import java.text.DecimalFormat;

//
//This class implements a temperature data type.
//
public class Temperature implements Comparable{

	public enum Units {
		CELSIUS, FAHRENHEIT, KELVIN;
	};

	public static class InvalidTemperatureUnitException extends Exception{

		/**
		 * 
		 */
		private static final long serialVersionUID = 3755108601677734615L;

		InvalidTemperatureUnitException(String message){
			super(message);
		}
	}

	private	double temp;			//Temperature in degrees Celsius.
	private Units displayUnits;		//Unit's to display

	//Default Constructor
	public Temperature(){

		setTemperature(0.0,Units.CELSIUS);
	}

	//
	//Constructor sets the temperature to the parameter.
	//Note: newTemp is assumed to be in units specified by newUnits and will be converted to
	//Celsius if newUnits != Units.Celsius.
	//
	public Temperature(double newTemp, Units newUnits){

		setTemperature(newTemp,newUnits);
	}

	//
	//Initialization Constructor.
	//Note: newTemp is assumed to be in units specified by newUnits and will be converted to
	//Celsius if newUnits != Units.Celsius.
	//
	public Temperature(double newTemp, String newUnits) 
			throws InvalidTemperatureUnitException{

		setTemperature(newTemp,newUnits);
	}

	//
	//Sets the temperature to newTemp.
	//Note: newTemp is assumed to be in units of newUnits.
	//
	public void setTemperature(double newTemp, Units newUnits){

		displayUnits = newUnits;

		switch(displayUnits){

		case CELSIUS:
			temp = newTemp;
			break;
		case FAHRENHEIT:
			temp = fahrenheitToCelsius(newTemp);
			break;
		default:
			temp = kelvinToCelsius(newTemp);
		}
	}

	//
	//Sets the temperature to newTemp.
	//Note: newTemp is assumed to be in units of stringNewUnits.
	//
	public void setTemperature(double newTemp, String stringNewUnits) 
			throws InvalidTemperatureUnitException{

		try{
			Units  newUnits = Units.valueOf(stringNewUnits);
			setTemperature(newTemp, newUnits);
		}

		catch(IllegalArgumentException e){

			String message = "\""+stringNewUnits+"\"" + "is not a valid temperature unit.";
			throw new InvalidTemperatureUnitException(message);
		}
	}

	//
	//Returns the value of temperature in units specified by displalyUnits.
	//
	public double getTemperature(){

		double t;

		switch(displayUnits){

		case FAHRENHEIT:
			t = celsiusToFahrenheit(temp);
			break;
		case KELVIN:
			t = celsiusToKelvin(temp);
		default:
			t = temp;
		}
		return t;
	}

	//
	//Returns the value of temperature in units specified by the units parameter.
	//
	public double getTemperature(Units units){

		double t;

		switch(units){

		case KELVIN:
			t = celsiusToKelvin(temp);
			break;
		case FAHRENHEIT:
			t = celsiusToFahrenheit(temp);
			break;
		default:
			t = temp;
		}

		return t;
	}

	//
	//Accessor.
	//
	public Units getUnits(){
		return displayUnits;
	}

	//
	//Returns a temperature whose value is the sum of this and rightOp and has the same units
	//as this.
	//
	public Temperature add(Temperature rightOp){

		//Compute the sum using the units of left operand.
		double sum = this.getTemperature() + rightOp.getTemperature(displayUnits);

		return new Temperature(sum, displayUnits);
	}

	//
	//A string representation of this.
	//
	@Override
	public String toString(){

		double value;
		String unitsAsString;

		switch(displayUnits){

		case FAHRENHEIT:
			value = celsiusToFahrenheit(temp);
			unitsAsString = "°F";
			break;
		case KELVIN:
			value = celsiusToKelvin(temp);
			unitsAsString = "K";
			break;
		default:
			value = temp;
			unitsAsString = "°C";
		}

		return new DecimalFormat("##.#").format(value) + unitsAsString;
	}

	//
	//Compares this to another Temperature and returns:
	//-1 if this < t. 	//+1 if this > t.
	//0 if this == t.
	//
	@Override
	public int compareTo(Temperature t) {

		int compare;

		if(t == null){
			throw new NullPointerException();
		}

		else if(getTemperature() < t.getTemperature(displayUnits)){ 			 			compare = -1; 		} 		 		else if(getTemperature() > t.getTemperature(displayUnits)){
			compare = 1;
		}

		else{
			compare = 0;
		}

		return compare;
	}

	private double celsiusToFahrenheit(double celsius){

		double fahrenheit = celsius * 180/100 + 32;

		return fahrenheit;
	}

	private double fahrenheitToCelsius(double fahrenheit){

		double celsius = (fahrenheit - 32) * 100/180;

		return celsius;
	}

	private double celsiusToKelvin(double celsius){

		double kelvin = celsius + 273;

		return kelvin;
	}

	private double kelvinToCelsius(double kelvin){

		double celsius = kelvin - 273;

		return celsius;
	}
}

package jwarren.lab1;
import java.util.LinkedList;

//
//This class maintains a record of temperatures and related statistics.
//
public class TemperatureRecord extends LinkedList{

	/**
	 * 
	 */
	private static final long serialVersionUID = -9095126012449179697L;

	//
	//Returns the highest Temperature in this record.
	//
	public Temperature getHighest(){

		Temperature highest = null;

		for(Temperature t : this){

			if( (highest == null) || ( highest.compareTo(t) < 0  ) ){ 				highest = t; 			} 		} 		 		return highest; 	} 	 	// 	//Returns the lowest Temperature in this record. 	// 	public Temperature getLowest(){ 		 		Temperature lowest = null; 		 		for(Temperature t : this){ 			 			if( (lowest == null) || ( lowest.compareTo(t) > 0 ) ){
				lowest = t;
			}
		}

		return lowest;
	}

	//
	//Returns the sum of all Temperatures in this record.
	//
	public Temperature getSum(){

		Temperature sum = null;

		for(Temperature t : this){

			if(sum != null){
				sum = sum.add(t);
			}

			else{
				sum = t;
			}
		}

		return sum;
	}

	//
	//Returns the avg of all Temperatures in this record.
	//
	public Temperature getAvg(){

		Temperature sum = getSum();
		double avg = sum.getTemperature() / size();

		return new Temperature(avg, sum.getUnits());
	}

}

package jwarren.lab1;
import java.util.Random;

//
//A class to simulate seasonal temperatures.
//
public class TemperatureSimulator {

	//Spring simulating constants.
	public static final int WINTER_MIN = 20;
	public static final int WINTER_MAX = 40;
	public static final int SPRING_MIN = 40;
	public static final int SPRING_MAX = 70;
	public static final int SUMMER_MIN = 70;
	public static final int SUMMER_MAX = 90;
	public static final int FALL_MIN = 40;
	public static final int FALL_MAX = 60;

	//Random number generator.
	private Random rng;

	//
	//Default Constructor
	//
	public TemperatureSimulator(){

		rng = new Random();
	}

	//
	//Returns a random number between WINTER_MIN and WINTER_MAX (inclusive).
	//
	public int getWinterTemp(){

		int rand = WINTER_MIN + rng.nextInt(WINTER_MAX-WINTER_MIN + 1);

		return rand;
	}

	//
	//Returns a random number between SPRING_MIN and SPRING_MAX (inclusive).
	//
	public int getSpringTemp(){

		int rand = SPRING_MIN + rng.nextInt(SPRING_MAX-SPRING_MIN + 1);;

		return rand;
	}

	//
	//Returns a random number between SUMMER_MIN and SUMMER_MAX (inclusive).
	//
	public int getSummerTemp(){

		int rand = SUMMER_MIN + rng.nextInt(SUMMER_MAX-SUMMER_MIN + 1);;

		return rand;
	}

	//
	//Returns a random number between FALL_MIN and FALL_MAX (inclusive).
	//
	public int getFallTemp(){

		int rand = FALL_MIN + rng.nextInt(FALL_MAX-FALL_MIN + 1);;

		return rand;
	}
}

Screenshots:

lab2

Leave a Reply

Your email address will not be published. Required fields are marked *