/** * This class defines a menu-driven application to record and display orders for * various types of fast food (pizza by the slice and chili by the cup or bowl) * in a restaurant. * * It demonstrates the advanced object-oriented features of inheritance, * polymorphism, and late binding. * * Written by: Jon Huhtala */ public class App { // The main entry point for the application. public static void main (String[] args) { // Variable for holding the number of orders. int noOrders = 0; // Constant specifying the maximum number of orders. final short MAX_ORDERS = 300; // Variable for holding the user's menu choice. byte choice = 0; // Constants used as case selectors. Each of these corresponds to a menu // choice available to the user. final byte ORDER_PIZZA = 1; final byte ORDER_CHILI = 2; final byte SHOW_ORDERS = 3; final byte EXIT = 4; // Array of superclass object references. Each element can be used to point // to subclass objects. FastFood[] orders = new FastFood[MAX_ORDERS]; // THE MAIN PROCESSING LOOP of the program. It handles the processing of a // single user menu response and is repeated until the user wants to exit. while (choice != EXIT) { // Display the menu, read the user's response, and draw a separator // before processing their request. Utility.separator(80,'/'); System.out.println("FAST FOOD MENU"); Utility.skip(); System.out.println(" 1 Order pizza by the slice"); System.out.println(" 2 Order chili by the cup or bowl"); System.out.println(" 3 Show order(s)"); System.out.println(" 4 Exit"); Utility.skip(); System.out.print("Enter menu choice: "); choice = Keyboard.readByte(); Utility.separator(80, '/'); // This switch statement is used to direct the logic flow based upon // the user's menu selection. switch (choice) { // This case instantiates a Pizza object. Order details will be obtained // after the end of this switch. case ORDER_PIZZA: // Instantiate a Pizza object and store its address in the // next available array location. orders[noOrders] = new Pizza(noOrders + 1); // Break out of the switch. break; // This case instantiates a Chili object. Order details will be obtained // after the end of this switch. case ORDER_CHILI: // Instantiate a Chili object and store its address in the // next available array location. orders[noOrders] = new Chili(noOrders + 1); // Break out of the switch. break; // This case displays all orders. case SHOW_ORDERS: // If no orders have been entered, display a message. if (noOrders == 0) { System.out.println("\t" + "No orders have been recorded"); } // Otherwise, list them. else { // Loop to display each order. for (int i = 0; i < noOrders; i++) { // Use late binding to call the showOrder() method of // the object being referenced. orders[i].showOrder(); } } // Break out of the switch. break; // This case handles a user's request to exit. All it does is break out // of the switch. case EXIT: break; // This is the default case. We get here when the user enters a menu // choice that doesn't match any of the above cases. default: // Display an error message indicating the user made an invalid // menu selection and break out of the switch. System.out.println("\t" + "Invalid menu choice - try again"); break; } // If a FastFood object was instantiated within the switch, get // order details from the user and increment the number of orders. if (orders[noOrders] instanceof FastFood) { // Get order details from the user. The proper takeOrder() method will // be called due to late binding. orders[noOrders].takeOrder(); // Increment the number of orders. noOrders++; } } } } // This is an abstract superclass that encapsulates common data and processing // of fast food orders. Because it is abstract, it can never be instantiated. abstract class FastFood { // Private instance variables for order number and amount due. private int orderNumber; private double amountDue; // This constructor accepts one parameter - the order number. It uses the // value to initialize the order number and sets the amount due to zero. public FastFood(int iOrderNumber) { orderNumber = iOrderNumber; amountDue = 0; } // This method can be called to set a new value for the order number. public void setOrderNumber(int newOrderNumber) { orderNumber = newOrderNumber; } // This method can be called to set a new value for the amount due. public void setAmountDue(double newAmountDue) { amountDue = newAmountDue; } // This method can be called to get the value of the order number. public int getOrderNumber() { return orderNumber; } // This method can be called to get the value of the amount due. public double getAmountDue() { return amountDue; } // ABSTRACT METHODS TO BE OVERRIDDEN BY SUBCLASSES. Each subclass must provide // its own definition. // This abstract method must be overridden by a subclass to take order // information. public abstract void takeOrder(); // This abstract method must be overridden by a subclass to display order // information. public abstract void showOrder(); } // This is a subclass of the FastFood class that encapsulates data and // processing of an order for chili by the cup or bowl. class Chili extends FastFood { // Public constants for sizes. public static final char CUP = 'C'; public static final char BOWL = 'B'; // Public constants for prices. public static final double CUP_PRICE = 1.00; public static final double BOWL_PRICE = 1.75; // Private instance variables for size and "heat level". private char size; private boolean isHot; // This constructor accepts one parameter (order number) and passes it through // to the superclass constructor. The size and "heat level" are set to default // values. public Chili(int iOrderNumber) { super(iOrderNumber); size = CUP; isHot = false; } // This method can be called to set a new value for the size. public void setSize(char newSize) { size = newSize; } // This method can be called to set a new value for the "heat level". public void setIsHot(boolean newIsHot) { isHot = newIsHot; } // This method can be called to get the value of the size. public char getSize() { return size; } // This method can be called to get the value of the "heat level". public boolean getIsHot() { return isHot; } // This method implements the abstract method of the superclass to take // information about a chili order from the user. public void takeOrder() { // This loop asks the user for the size. Their reply must be either a CUP or // a BOWL. If the respond correctly, the size and price are set. Otherwise, // the loop continues until they get it right. do { // Prompt for size and read user reply. System.out.print("Enter size ('C' for cup, 'B' for bowl): "); size = Keyboard.readChar(); // Process the size. switch (size) { // This case sets the size and price for a cup. case CUP: case 'c': setSize(CUP); setAmountDue(CUP_PRICE); break; // This case sets the size and price for a bowl. case BOWL: case 'b': setSize(BOWL); setAmountDue(BOWL_PRICE); break; // This case handles an invalid size specification. default: System.out.println("\t" + "Invalid size specified"); } } while (!(size == CUP || size == BOWL)); // Ask the user for the "heat level" and set their reply. System.out.print("Extra HOT? (true or false): "); isHot = Keyboard.readBoolean(); } // This method implements the abstract method of the superclass to display // one line of information about a chili order. public void showOrder() { // Display the order number. System.out.print("\t" + getOrderNumber() + ") "); // Display the size. if (size == CUP) { System.out.print("One cup of "); } else { System.out.print("One bowl of "); } // Display the "heat level". if (isHot) { System.out.print("extra HOT chili - "); } else { System.out.print("regular chili - "); } // Display the amount due. System.out.println(Utility.moneyFormat(getAmountDue())); } } // This is a subclass of the FastFood class that encapsulates data and // processing of an order for pizza by the slice. class Pizza extends FastFood { // Public class constant for the price of each slice. public static final double PER_SLICE = 1.50; // Private instance variables for the number of slices and the topping. private byte numberOfSlices; private String topping; // This constructor accepts one parameter (order number) and passes it through // to the superclass constructor. The number of slices and topping are set to // default values. public Pizza(int iOrderNumber) { super(iOrderNumber); numberOfSlices = 1; topping = "Cheese"; } // This method can be called to set a new value for the number of slices. public void setNumberOfSlices(byte newNumberOfSlices) { numberOfSlices = newNumberOfSlices; } // This method can be called to set a new value for the topping. public void setTopping(String newTopping) { topping = newTopping; } // This method can be called to get the value of the number of slices. public byte getNumberOfSlices() { return numberOfSlices; } // This method can be called to get the value of the topping. public String getTopping() { return topping; } // This method implements the abstract method of the superclass to take // information about a pizza order from the user. public void takeOrder() { // Ask the user for the number of slices. Their reply can't be less than // or equal to zero. do { System.out.print("Enter number of slices: "); numberOfSlices = Keyboard.readByte(); if (numberOfSlices <= 0) { System.out.println("\t" + "Invalid number of slices"); } } while (numberOfSlices <= 0); // Ask the user for the choice of topping. System.out.print("Enter choice of topping: "); topping = Keyboard.readString(); // Calculate and set the amount due for this order. setAmountDue(numberOfSlices * PER_SLICE); } // This method implements the abstract method of the superclass to display // information about a pizza order. public void showOrder() { // Display a single line of information about the pizza order. System.out.println("\t" + getOrderNumber() + ") " + numberOfSlices + " slice(s) of " + topping + " pizza - " + Utility.moneyFormat(getAmountDue()) ); } }