One of the most often cited benefits of object oriented design is generalization. Generalization, however, can take several forms. One form is through reuse of components. In theory, a task or problem can divided into a set of basic components so that the classes that implement them can be used in different parts of the overall system or in different systems that include similar function. As an example of the first type, databeans are used in some designs to transfer collections of related variables from one method or layer to another and, thus, they are used by many different classes. As an example of the second type, many different applications that include a login component might reuse the same layered classes and authentication function that form a path from user interface to database and back..
Another form of generalization is through inheritance or extension. A class can be defined that supports a set of generic functions for a particular type of data. Subclasses can then add function and/or properties to the original (super)class. For example, a DataBean class might include properties for the id or key for a database entry, the owner, a name for the object, and date created and date modified values. These data would be appropriate for many different kinds of objects and the tables that provide persistent storage for them. More specialized beans might then extend DataBean by adding other properties appropriate for a type. For example, a PersonBean might include an individual's address, phone numbers, email and url listings, etc. Similar beans might be defined for a Company, an Order, or an OrderItem. All could extend DataBean, or a hierarchy might be discovered such that some set of intermediate beans extend DataBean, but other subclasses derive from them.
Reuse and inheritance are forms of generalization that potentially apply to any Java design. However, for J2EE layered designs, they can be especially helpful when used in combination with one another. When a database is used for persistence, many types of data will require a set of functions that has become known as CRUD: Create, Retrieve, Update, and Delete. I would add a general Search function to this list, producing the acronym CRUDS. If the various properties that comprise a particular data type are collected into a databean and if these databeans pass through the various layers of a typical J2EE design, each layer is likely to provide the basic set of CRUDS methods and, possibly, other specialized methods. Considerable benefit can be gained if the core CRUDS methods for a given layer are implemented in a superclass that applies to any databean. Thereby, subclasses that extend the superclass implement the abstract datatype-specific methods and any additional methods that might be required for that type.
Superclassing core CRUDS function for J2EE layered systems can reduce not only the volume of code but also its complexity. Subclass methods are often small, easy to build support methods. However, working out the details of actually how to build the super/subclass structures for each layer can be challenging since different layers require different approaches and/or designs. One cannot build super/subclass combinations the same way in a Struts Control layer as in a straight Java layer, such as a Domain Mapper layer, and Session EJBs require still a different approach.
The discussion that follows will consider generalizing J2EE layered designs using the approach described above. The majority of the discussion will concern four specific J2EE layers. All require a hierarchy of databeans. In each layer, a superclass will include key variables and one or more implemented methods that provide the core CRUDS function for that layer. Each superclass also includes a number of abstract methods. As a result, subclass coding consists largely of implementation those abstract methods along with any additional methods required for a particular subclass or type of databean. Each of the four layers is illustrated by an example, and the accompanying discussion points out peculiarities for that layer.
J2EE Layers
A seven layer architecture will be used in this discussion, consisting of the following:
- View
- Control
- UI Model
- Session EJB
- Domain Mapper
- Entity EJB
- DBMS
Generalization is discussed for layers 2 through 5 -- Control, UI Model, Session EJB, and Domain Mapper. These are the central layers that often provide similar function for many different types of data. Since objects in each layer call methods on objects in a lower layer, the layers are discussed in back to front order.
Generalization is not considered for layers 1, 6, and 7 -- View, Entity EJB, and DBMS -- since they are data type specific.
Example System
Examples used to illustrate generalization in the various levels are all taken from a system called the Object Oriented Content System (OOC). It is a research system being developed at the University of North Carolina to explore the application of O-O concepts to documents and other forms of information. A brief description of that system is included to provide context for the discussions that follow.
Domain Mapper Layer
The Domain Mapper layer is the context in which most business logic and/or semantic processing takes place. It resides between the EJB Session and the EJB Entity layers. It is implemented using conventional Java classes and, hence, can be built in a relatively straight forward fashion using inheritance, abstract methods, and EJB superclasses for generic references to the EJB Entity layer.
Session EJB Layer
The Session EJB layer provides the API to the application Domain. It resides between the UI Model and the Domain Mapper layers. From a best practices perspective, its primary function is to provide contexts for transactions and access control at the method level. Because of constraints imposed by the J2EE EJB 2.0 standard and the WebSphere implementation, it cannot be implemented in a straight forward manner by creating a superclass Session EJB and extending it for subclasses. A solution, developed by one of us (Brown), uses inheritance and abstraction, but outside the EJB class hierarchy.
UI Model Layer
The UI Model layer may be found more in pedagogical contexts than in industry systems. The EJB Session layer provides the Domain API, which can function as the model layer in a Mode-View-Control architecture. However, this structure imposes heavy learning curve requirements for novice J2EE programmers who may be building systems from the UI back and wish to test their view and control components with stubbed models. The UI Model layer provides a context for thin or stubbed models without requiring the programmer to confront the complexity of the EJB Container, specification, and development tools.
It resides between the UI Control layer and the Session EJB layer. Like the Domain Mapper layer, it is implemented using conventional Java classes and, hence, can be built using inheritance and abstract methods.
Struts Control Layer
The Control layer is responsible for UI navigation. Its main functions are to determine the user's intent, pass data received from the UI component to the model, receive results from the model, and determine the next UI component to present to the user. Thus, it resides between the View layer and the Model layer in a M - V - C architecture.
The Control layer discussed here is based on the Struts framework in which an Action class provides the main control function. Generalization is achieved through inheritance and abstract methods; however, subclasses must also override the super class's execute method, resulting in a different design and implementation strategy.