Keywords: current

Next: 1.5.4 Inheritance and the Up: 1.5.3 Singleton Pattern Previous: 1.5.3.3 Maintaining Sample Test

### 1.5.3.4 A Sample Program

We are now ready to define a simple program to sum the integers in a lists. We will add a definition of the method

> `int sum();`

to each class in our composite class hierarchy for `IntList`. Let's begin by writing the contract and header for `sum` in the abstract class `IntList`:

    // IntList := Empty() + Cons(Object, IntList)

    abstract class IntList {
      ...
      abstract int sum();
      // returns the sum of the numbers in this
    }

Next we need to generate examples showing the expected behavior of the method:

    /** IntList := Empty() + Cons(Object, IntList) */
    abstract class IntList {
      ...
      abstract int sum();
      // returns the sum of the numbers in this
    }

    class IntListTest() {

      static final oneElt  = new Cons(1, Empty.ONLY);
      static final twoElts = new Cons(5, oneElt);
      static final threeElts = new Cons(-10, twoElts);

      /** Given the the answer ans, computes the sum() on this and
       *  compares it against ans.  If the values disagree, it throws an
       *  exception with an embedded error message; otherwise it
       *  silently returns.
       */

      void test(IntList input, int ans) {
        int result = sum();
        if (result != ans) throw new
          RuntimeException("Test FAILURE: computed answer is: " + result +
                           " correct answer is: " + ans);
        }

      void sumTest() {
        test(Empty.ONLY, 0);
        test(oneElt, 1);
        test(twoElts, 6);
        test(threeElts, -4)
      }
    }

The `test` and `sumTest` methods both have result type `void`, which is the degenerate, empty type. There are no values of type `void`. A method with `void` return type does not return a value. When running a program test, we want the test to ``silently'' return (indicating successful completion) unless there is an error, which generates an exception aborting the execution of the test.

As the fourth step, we select a template for writing the `sum` method, which for methods on composite hiearchies like `IntList` is usually the interpreter pattern:

    class Empty {
      ...
      int sum() { ... }
    }

    class Cons extends IntList {

      int first;
      IntList rest;
      ...
      int sum() { ... first  ... rest.sum() ... ; }
    }

Finally, we complete the coding process by filling in the bodies of the methods in the template:

    class Empty {
      ...
      int sum() { return 0; }
    }

    class Cons extends IntList {

      int first;
      IntList rest;
      ...
      int sum() { return first + rest.sum(); }
    }

To finish the design recipe, we test our code using the examples in the `main` method of `IntList`.

Finger Exercise: Load your saved file `IntList.java` into DrJava Definitions pane. Define the `sum` method as described above. Try some simple tests in the interactions pane to convince yourself that your `IntList` class (including the `sum` method is correctly coded.

Next add the `IntListTest` class to your program in the `Definitions` pane. In the Interactions pane, run the tests specified in the method invocation `new IntListTest().sumTest()`. The method should silently return if you coded everything correctly.

Using the same design recipe, add a definition of a method `prod` to compute the product of a list of numbers and test it. Note that the Data Analysis and Design step has already been done in the definition of the `IntList` hierarchy. Save your revised program in the file `IntList.java`.

Next: 1.5.4 Inheritance and the Up: 1.5.3 Singleton Pattern Previous: 1.5.3.3 Maintaining Sample Test