JMU JMU - Department of Computer Science
Help Tools
Lab: Experimenting with Polymorphism through Interfaces


Instructions: Answer the following questions one at a time. After answering each question, check your answer (by clicking on the check-mark icon if it is available) before proceeding to the next question.

Getting Ready: Before going any further, you should:

  1. Depending on your development environment, create either a directory or a project for this lab.
  2. Setup your development environment.
  3. Download the following files:
    to an appropriate directory/folder. (In most browsers/OSs, the easiest way to do this is by right-clicking/control-clicking on each of the links above and then selecting Save as... or Save link as....)

1. Making a Class Polymorphic using an Interface: This part of the lab will help you understand one of the important uses of interfaces (and the importance of polymorphism).
  1. Add either DukulatorWindow.jar or DukulatorWindow.class and dukulator.gif to your directory/project.
  2. Add Dukulator.java, IntegerCalculator.java, and ExpressionObserver to your directory/project.
  3. Open the source code for the Dukulator class.
  4. Compile, execute and test the Dukulator class. (Note: Depending on your development environment, you may need to execute the application from the command line.)
  5. What aspects of the Dukulator did not work properly?


    One could enter expressions but the Dukulator did not evaluate them.
    Expand
  6. Open the source code for the ExpressionObserver interface and the IntegerCalculator class.
  7. As you can see, an ExpressionObserver is an object that knows how to evaluate a String representation of an expression and return a String representation of the result. Add a "clause" to the declaration of the IntegerCalculator class so that it claims to implement this interface.
  8. What "clause" did you add?


    implements ExpressionObserver
    
    Expand
  9. Add a method to the IntegerCalculator class so that it actually does implement the ExpressionObserver interface. This method must use the calculate() method and must return the String "Error" if the calculate() method throws an exception.
  10. What code did you add?


        /**
         * Evaluate an expression and return a String representation of
         * the result (required by ExpressionObserver)
         *
         * @param expression   The expression to evaluate
         * @return             The result (or "Error")
         */
        public String evaluate(String expression)
        {
           String    result;
           
    
           try
           {
              result = "" + calculate(expression);          
           }
           catch (Exception e)
           {
              result = "Error";          
           }
    
           return result;       
        }
    
    Expand
  11. The DukulatorWindow is a GUI window that contains a "soft" numeric keypad and a one-line display. Familiarize yourself with the behavior of this class by reading the descriptions of the following methods:
        /**
         * Default Constructor
         */
        public DukulatorWindow()
    
    
    
        /**
         * Set the ExpressionObserver that should be notified when
         * the = button is pressed
         *
         * @param observer   The observer to notify
         */
        public void setExpressionObserver(ExpressionObserver observer)
        
  12. Since your IntegerCalculator class is now an ExpressionObserver you can now tell a DukulatorWindow object to call your IntegerCalculator when the = button is pressed.

    Modify the Dukulator class so that it constructs an IntegerCalculator and associates it with the DukulatorWindow.

  13. What code did you add?


           IntegerCalculator      calculator;
    
           calculator = new IntegerCalculator();
           
           window.setExpressionObserver(calculator);       
    
    Expand
  14. Compile, execute, and test the Dukulator class. (Note: Depending on your development environment, you may need to execute the application from the command line.)
  15. Did it work properly?


    Yes.
    Expand
  16. How did polymorphism come into play in this example?


    The IntegerCalculator class can now take the form of an ExpressionObserver. This enabled us to associate it with a DukulatorWindow even though such objects know nothing about the IntegerCalculator class.
    Expand
2. Polymorphism, Overloading and Parameters: This part of the lab will help you gain a better understanding of passing polymorphic objects to overloaded methods.
  1. Add Taxable.java, AccountDriver.java, and Account.java to your directory/project.
  2. Open and read Taxable.java, AccountDrive.javar, and Account.java.
  3. What overloaded methods are in AccountDriver?


    It contains three summarize() methods, one that is passed an Account, one that is passed a Comparable, and one that is passed a Taxable.
    Expand
  4. Compile AccountDriver.
  5. fred is declared to be a Comparable but instantiated as an Account, and wilma is declared to be a Taxable but instantiated as an Account. Why does AccountDriver compile without generating any error messages?


    Account "is a" Comparable and it "is a" Taxable since it implements/realizes the Comparable and Taxable interfaces.
    Expand
  6. In the main() method of AccountDriver, after the initialization statements, add a call to summarize() passing it the object named barney.
  7. What code did you add?


           summarize(barney);       
    
    Expand
  8. Compile and execute AccountDriver.
  9. What output was generated?


    This Account has a balance of: 1000.0
    
    Expand
  10. Why was this output generated?


    When the compiler got to the call to summarize() in main(), it needed to look for a summarize() method that can be passed the object named barney. It found three (since barney is declared to be an Account and the Account class implements the Comparable and Taxable interfaces. Since barney is declared to be an Account and there is a version that is passed an Account it used that one.
    Expand
  11. Comment-out the summarize() method that is passed an Account object.
  12. Compile AccountDriver.
  13. What error message was generated?


    AccountDriver.java:22: reference to summarize is ambiguous, both method summariz
    e(java.lang.Comparable) in AccountDriver and method summarize(Taxable) in Accoun
    tDriver match
           summarize(barney);
           ^
    1 error
    
    Expand
  14. Why was this error message generated?


    When the compiler got to the call to summarize() in main(), it needed to look for a summarize() method that can be passed the object named barney. It found two (since barney is declared to be an Account and the Account class implements the Comparable and Taxable interfaces. It has no way to choose between them and, so, says the statement is ambiguous.
    Expand
  15. Remove the comments from the summarize() method that is passed an Account object. (That is, the AccountDriver class should again have three summarize() methods.
  16. Modify the call to summarize() so that it now passes fred instead of barney.
  17. What does that statement look like after the modification?


           summarize(fred);       
    
    Expand
  18. Compile and execute AccountDriver.
  19. What output was generated?


    This is, indeed, a Comparable
    
    Expand
  20. Why was this output generated?


    When the compiler got to the call to summarize() in main(), it needed to look for a summarize() method that can be passed the object named fred. fred is declared to be a Comparable so it only found one such method.

    Even though, at run-time, fred will actually be an Account object, the compiler can't always know that. So, it uses the declared type.

    Expand
3. Interfaces, Polymorphism, and GUIs: This part of the lab will help you learn how to use interfaces and polymorphism to build classes that contain the "application logic" for GUI-based applications.
  1. Add either ControllableAlarmClock.jar or ControllableAlarmClock.class and clock.gif to your directory/project.
  2. Add ClockDriver.java and AlarmController.java to your directory/project.
  3. Open the source code for the ClockDriver class.
  4. Compile, execute (perhaps from the command line) and test the ClockDriver class. (Note: The information at the bottom of the clock shows the state of the alarm settings. The buttons/checkbox are for changing the alarm settings.)
  5. What aspects of the clock did not work properly?


    One could press the buttons/checkbox but nothing changed as a result.
    Expand
  6. The ControllableAlarmClock is a GUI window that contains a "display" and "controls" for an alarm clock. Familiarize yourself with the behavior of this class by reading the descriptions of the following methods:
        /**
         * Default Constructor
         *
         * Construct an AlarmClock for your "home" city
         */
        public ControllableAlarmClock()
    
    
    
        /**
         * Explicit Value Constructor
         *
         * Construct an AlarmClock for the given city
         * (Note: Not all city names are recognized)
         */
        public ControllableAlarmClock(String city)
    
    
    
    
    
    
        /**
         * Add an ActionListener to the buttons on the alarm setter
         *
         * @param listener   The ActionListener
         */
        public void addActionListener(ActionListener listener)
    
    
    
        
    
        /**
         * Get the AMPM setting on the alarm
         *
         * @return   "AM" or "PM"
         */
        public String getAlarmAMPM()
        
    
    
    
        /**
         * Get the hour setting on the alarm
         *
         * @return   The hour setting on the
         */
        public int getAlarmHour()
    
    
        /**
         * Get the minute setting on the alarm
         *
         * @return   The minute setting on the
         */
        public int getAlarmMinute()
    
    
    
        /**
         * Is the alarm on?
         *
         * Note: This method does not check to see if the alarm is currently
         * beeping.  It checks to see if the alarm will beep when at
         * the appropriate time
         *
         * @return true if the alarm is currently on; false otherwise
         */
        public boolean isAlarmOn()
    
    
    
        /**
         * Set the hour of the alarm
         *
         * @param hour     The hour of the alarm
         */
        public void setAlarmHour(int hour)
    
    
    
        /**
         * Set the minute of the alarm
         *
         * @param minute   The minute of the alarm
         */
        public void setAlarmMinute(int minute)
    
    
    
        /**
         * Set the AM/PM of the alarm
         *
         * @param ampm     "AM" for before noon, "PM" for noon and after
         */
        public void setAlarmAMPM(String ampm)
    
    
    
        /**
         * Turn the alarm off
         */
        public void turnAlarmOff()
    
    
    
        /**
         * Turn the alarm on
         */
        public void turnAlarmOn()
    
        
  7. Familiarize yourself with the ActionListener java.awt.event.ActionListener interface. (This interface is part of the Java library that is used to develop graphical user interfaces. It has one method, actionPerformed(). This method is called when buttons/checkboxes are pressed.)
  8. Familiarize yourself with the ActionEvent.getActionCommand() java.awt.event.ActionEvent#getActionCommand() method in the java.awt.event.ActionEvent class. (This class is also part of the Java library that is used to develop graphical user interfaces. This method returns a String that can be used to identify the button/checkbox that was pressed.)
  9. Modify the actionPerformed method in the AlarmController class so that it prints the String description of the button/checkbox that was pressed. (Note: At this point, the AlarmController will not respond to buttons/checkboxes. You'll fix that shortly.)
  10. What code did you add?


        System.out.println(ac);
    
    Expand
  11. Modify the ClockDriver class. It must now also:
    • Declare an AlarmController object named controller.
    • Construct controller (passing the constructor clock).
    • Call the clock object's addActionListener() method, passing it controller.
  12. What code did you add?


           AlarmController               controller;
    
    
    
           controller = new AlarmController(clock);
           clock.addActionListener(controller);
    
    Expand
  13. Compile and execute the ClockDriver class. (Note: You may need to execute the application from the command line.)
  14. What String is associated with each button/checkbox in the ControllableAlarmClock?


    HOUR_UP
    HOUR_DOWN
    MINUTE_UP
    MINUTE_DOWN
    AMPM_CHANGE
    ON_OFF
    
    Expand
  15. Add the following code to the the actionPerformed method in the AlarmController class:
           int      value;
           String   ampm;
    
    
           if      (ac.equals("HOUR_DOWN"))
           {
              value = clock.getAlarmHour();
              value--;
              if (value < 1) value = 12;          
              clock.setAlarmHour(value);          
           }
           else if (ac.equals("HOUR_UP"))
           {
              value = clock.getAlarmHour();
              value++;
              if (value > 12) value = 1;          
              clock.setAlarmHour(value);          
           }
        
  16. Compile the AlarmController class and execute and test the ClockDriver class. (Note: You may need to execute the application from the command line.)
  17. What works and what doesn't?


    The hour for the alarm can now be changed but nothing else can.
    Expand
  18. Modify the actionPerformed() method in the AlarmController class so that everything works properly.
  19. What code did you add?


           else if (ac.equals("MINUTE_DOWN"))
           {
              value = clock.getAlarmMinute();
              value--;
              if (value < 0) value = 59;          
              clock.setAlarmMinute(value);          
           }
           else if (ac.equals("MINUTE_UP"))
           {
              value = clock.getAlarmMinute();
              value++;
              if (value > 59) value = 0;          
              clock.setAlarmMinute(value);          
           }
           else if (ac.equals("AMPM_CHANGE"))
           {
              ampm = clock.getAlarmAMPM();
              if (ampm.equals("AM")) clock.setAlarmAMPM("PM");
              else                   clock.setAlarmAMPM("AM");
              
           }
           else if (ac.equals("ON_OFF"))
           {
              if (clock.isAlarmOn()) clock.turnAlarmOff();
              else                   clock.turnAlarmOn();
           }
    
    Expand

Copyright 2021