Skip to main content.

Thursday, January 19, 2006
Due: Wednesday, January 25, 2006 - 10:00PM

 
>> Homework Exercises

Preliminaries

Yesterday, we went over an example of some classes to compute the average and maximum of a set of input values. First we started with an IntDataSet class that maintained statistics for a set of numbers. Then, I showed you a copy/paste version of that class - renamed to BankDataSet - that processed a set of BankAccount objects and their balances. I also mentioned how, if we wanted then to process Coin objects, we would have to make another slightly modified copy of the IntDataSet class.

In each case, the basic functionality of the DataSet class was the same; the only difference was in how to figure out the measurement to use when calculating the sum and maximum values. If our classes (BankAccount and Coin, for example) could agree on a single, common method for returning the measure needed by the data analysis, then we could program a reusable DataSet class.

Preparing the BankAccount and Coin classes

1.

In your Eclipse workspace, start a new project called "lab02". Copy the following code files into your project:

2.

Our first step will be to specify a common method that both the BankAccount and Coin classes will use to return a measure. We do this by defining a Java interface. A Java interface type declares a set of methods and their signatures (headers), but unlike a class, provides no fields or method implementations. Interfaces are used to specify required operations that must be supported by a set of classes.

In your "lab02" project, create a new Java interface called "Measurable". Fill in the body of the interface as follows:

/** Interface for classes supporting some sort of measure operation */
public interface Measurable {
   double getMeasure();
}

3.

Now, we will make the BankAccount and Coin classes implement this interface -- i.e. they implement the method(s) that the interface requires.

First, add the clause "implements Measurable" to the header of the BankAccount class:

public class BankAccount implements Measurable {

If you save the file at this point, you will see that the compiler gives you an error: "The type BankAccount must implement the inherited abstract method Measurable.getMeasure()". This means that we have claimed that the BankAccount class supports the Measurable interface, but we haven't yet defined a getMeasure() method for the BankAccount. So, at the bottom of the BankAccount class, add a getMeasure() method:

   public double getMeasure() {
      return balance;
   }

4.

Now, following a similar process as in Step 3 above, make the Coin class implement the Measurable interface.

Writing a reusable DataSet class

You can now write a DataSet class that will work with any objects supporting the Measurable interface.

  1. First, create a new class in Eclipse called "DataSet".

  2. Copy and paste the implementation of the IntDataSet class into the DataSet class, changing the names "IntDataSet" to "DataSet" as appropriate.

  3. Change the type of the maximum field from double to Measurable.

  4. Now make appropriate changes to the rest of the DataSet class -- e.g. the add method should take a parameter x of type Measurable instead of double, and it should call the getMeasure() method of the x object to add it to the sum; the getMaximum() method should return a Measurable object instead of a double; etc.

  5. If you have any errors you can't get rid of, ask me.

Your DataSet class should now be able to process objects of either BankAccount or Coin types, without any further modification. Copy the following main method into your DataSet class and verify that it compiles and runs:

   public static void main( String[] args ) {

      // Process some bank accounts using the DataSet class
      DataSet bankData = new DataSet();

      bankData.add(new BankAccount("John", 0));
      bankData.add(new BankAccount("Jill", 10000));
      bankData.add(new BankAccount("Jim", 2000));

      System.out.println("Average balance = " + bankData.getAverage());
      Measurable max = bankData.getMaximum();
      System.out.println("Highest balance = " + max.getMeasure());


      // Process some coin objects using the DataSet class
      DataSet coinData = new DataSet();

      coinData.add(new Coin(0.25, "quarter"));
      coinData.add(new Coin(0.1, "dime"));
      coinData.add(new Coin(0.05, "nickel"));

      System.out.println("Average coin value = " + coinData.getAverage());
      max = coinData.getMaximum();
      System.out.println("Highest coin value = " + max.getMeasure());
   }

Make sure you understand how things are working here. Notice the type of object returned by the getMaximum() method -- stored in the max variable. At one point the max variable refers to a BankAccount object, and later on in the main method it refers to a Coin object! But the fact that both those classes implement the Measurable interface means we can treat the objects as a 'Measurable ' object and call the getMeasure() method on it. But notice that although the calls to max.getMeasure() look exactly the same, they are calling two different methods in different classes. Try putting a debugging print statement in each of the getMeasure() methods to see this for sure. This feature of Java (and object-oriented programming in general) is called Polymorphism. If you don't understand what this paragraph is talking about, ask me.

Look at the diagram on page 413 in the textbook of the classes we have just worked on and read the two paragraphs above it.

Using interfaces for callbacks

There are two limitations of our design of the DataSet class above using the Measurable interface:

For the rest of lab, we will work together to redesign the DataSet class so both the limitations above are addressed.

Homework Exercises

Read the following article carefully and take it to heart: How NOT to go about a programming assignment

[60 points] Complete Programming Project 11.2 on page 441. The idea is to abstract out the functionality common to such two-player games and design an interface specifying the methods needed by such games in general. Given such an interface, you can then write the main game loop (consisting probably of displaying the board, figuring out whose turn it is, getting a player's move, checking and making the move, and then looping around again) independent of the particular game. By defining different classes that implement the interface, you can quickly build new games.

You do not have to use these files, but if you would like to see one solution to the game of Nim, here are some source code files: lab02/Pile.java lab02/ComputerPlayer.java lab02/HumanPlayer.java lab02/Game.java lab02/GameOfNim.java. Once you have designed your game playing interface, you may modify these files to fit it. You must also develop an implementation of a TicTacToe game for this assignment. The textbook has a portion of some TicTacToe code on pages 299-300.

Note: All source code that you produce must conform to the following style guide, adapted from the textbook's Appendix A: Java Programming Style Guide

Your completed source code files must be turned into the proper submit folder (submit02) by the deadline. (The submit folder will automatically be disabled when the deadline passes and you will not receive credit for the assignment.) I do not want emailed copies of your final programs. If you have problems connecting to the server, email me about it -- but not at 10:01pm! Read the "Late Work" policy on the course overview page.