Our first task in writing a program is to understand and define the data that the program will process. We must compile an inventory of the various forms of data that can appear as program inputs and outputs and determine how to represent their ``relevant'' properties as Java data objects. In scientific problem solving, this process is often called ``data modeling'' or simply ``modeling''. For each distinct form of data, we must define a Java class with fields that represent the relevant properties of each object of that form. We use the composite pattern to specify which different forms of data belong to the same more general category of data. In the preceding section, for example, we grouped the Empty department directory and non-empty Cons department directories together using the composite pattern to form the more general category DeptDirectory.
Java class definitions are more general and flexible than Scheme struct definitions because they enable the programmer to determine (i) exactly which primitive operations, including constructors, the new form of data will support, (ii) how objects will be printed as strings, (iii) and the types of object fields and methods. In Scheme, the set of operations generated by a struct definition is rigidly determined and Scheme does not include any provision for specifying the types of struct fields and operations.
The extra generality provided by Java comes at a price. A Java programmer must write far more text to define a class than a Scheme programmer does to define a comparable struct. Of course, some of the classes in a Java data definition, e.g., the abstract class at the top of a composite class hierarchy, have no analog in Scheme, forcing the Scheme programmer to write explanatory comments instead.
It is a good idea to define a collection of examples for each concrete class in a data definition. These examples can be defined as static fields of the class.