Design Recipe for Java Classes

Define the problem
State, clearly and unambiguously in English, what the class is supposed to do or represent. If you can't do this in English, you have no hope of doing it in Java.
List desired behaviors
List the services this class of objects is expected to provide for other objects.
This is also a good time to decide what information the class contains. For example, a Cons class would contain a "first" element and a "rest"; a Student class might contain a "name", a "SSNumber", a "GradePointAverage", etc. You'll also need to specify what types these are: in a Student class, the "name" would presumably be a String, the "SSNumber" (complete with its hyphens) probably also a String, and the "GradePointAverage" a double, while in a Cons class for a list of ints, the "first" element would be an int and the "rest" would be an IntList.
Define the interface
Describe these services more precisely in Java syntax. Typically, each "service" will become a method in the class. This is a good time to write the contract and examples for each of the methods.
Since you also decided, above, what information the class contains, you can now put this decision into Java syntax by writing instance variable declarations.
Write a class definition skeleton
This is just the standard syntax for a class, together with "placeholder" comments to remind yourself of where you're going to put the various methods and instance variables:

abstract class MyClass extends HisClass
   {
   // instance variable(s)

   // constructor(s)

   // access method(s)

   // I/O and conversion method(s)

   // interesting method(s)

   }

For each of the methods you defined in the previous step, categorize it and put its contract and examples into the appropriate place, in comments.

Write the methods
Writing methods is the part that takes the most thought, but it's not too bad if you've already done all of the above and you're not asking one method to do too much work. Follow the design recipe for Java methods.

I recommend writing method headers and examples for all the methods that you defined above, then picking one method at a time for filling in templates, filling in bodies, and testing. Choose methods in a "bottom-up" fashion: start with one that doesn't depend on any others, then one that depends on the first, etc.

I also recommend writing, before any other methods (or at least fairly early), a testing method:

 public static void test () {
    System.out.println ("Testing class-name.");
    System.out.println ();
    }
 
This doesn't do anything interesting yet (except tell you what class you're working on), but as you write each new method, you'll add its test cases to the body of the test method, and you can see whether it works simply by invoking the test method.
Alternatively, you can try individual test cases (in BlueJ or DrJava) by hand, but this is less and less convenient as the number of methods and test cases grows.
Test the class
In the course of the design recipe for methods, you've already tested each of the methods individually. But you're not finished: it is possible that some non-obvious interaction among the methods causes incorrect behavior. So now you need to test the class as a whole.

You should already have lines in your static void test() method that create a number of objects of the class, with different properties, try various individual methods on them, and print the results. Now start trying different sequences or combinations of operations on each object. If each such sequence of operations behaves as expected, you have reason to believe the class is correct. If not, you have a defect somewhere: you already have confidence in each method on its own, so the defect must be an interaction or misunderstanding between two or more methods (for example, there's a housekeeping chore to be done, and each method thinks the other is doing it so it doesn't get done, or both methods do it so it gets done twice).


Last modified: Mon Apr 10 16:59:12 EDT 2000
Stephen Bloch / sbloch@boethius.adelphi.edu