3.0.3 Configurable Algorithms
Not all technology implementations are exclusively interfaces. Most have a combination of generalized class definitions that interact with interface types. Consider the servlet package; it provides a javax.servlet.GenericServlet implementation that is defined abstractly along with providing a servlet interface type. While this may seem redundant, designers of the servlet API have provided a way for developers to take advantage of an abstract configurable algorithm, and have provided an abstract configurable implementation that can serve as the basis of a concrete implementation. (For more on this dual nature, see the discussion comparing abstract classes and interfaces.)
Abstract Classes or Interfaces?
Inheritance is a feature of the OO paradigm that captures the imagination of developers when they first encounter this technology. The ability to define and classify hierarchies of data structures and create state and behavior that is extended for specific functionalities provides an excellent way to deliver solutions that can be extended in a white box manner.
White box-based designs utilize inheritance by implementing a base class that is extended by developers, and the appropriate elements are overridden with the desired functionality. Java provides language constructs that help communicate what can and cannot be overridden at construction time. Methods and class definitions can be defined as abstract, requiring developers to supply concrete implementations. Access modifiers such as final and private can be utilized to prohibit methods from being overridden. Combining these elements effectively can yield what is referred to as a configurable algorithm. The base class implements generalized methods that perform a set of algorithmic steps. Within this scope of base methods calls, abstract methods appear that are overridden, fulfilling a given method's implementation.
Using inheritance exclusively can result in deep hierarchies that may lead to coupled implementations, usually the result of an abstract design that requires a large number of abstract methods to be implemented. Java interfaces provide an alternative abstract mechanism that allows for a more independent implementation without regard to an existing hierarchy.
Inheritance is useful for designs that have algorithms or behavior that can be generalized and utilized by extending classes. Designs that require most or all of its implementation to be defined by extending classes can be communicated using interface definitions. Implementers are given complete freedom in how the interface methods carry out their operations. However, interfaces enforce a more rigid contract, and changing an interface design can make a larger impact on existing implementations. Therefore, an effective way to evolve a design, in lieu of booking a lot of initial design time, is to initially utilize inheritances and let an abstract design evolve. Once the required signatures have been discovered, and it turns out that a configurable implementation is necessary, interface(s) can be produced.
Configurable implementations utilizing interfaces are the underpinnings of providing vendor-independent J2EE technology designs.
Interfaces and effective abstractions are the means by which J2EE components achieve vendor neutrality. The J2EE specifications simply define the APIs, types, life cycles, and interactions of objects within the technology frameworks. Vendors can then apply their efforts toward the agreed-upon contracts and specifications. Developers write to these specifications. You may ask: "Won't that create a dependency on these contracts, and if they change,won't my code be affected?" The short answer is yes, you are dependent upon versions of these contracts, but engaging them in a consistent way and knowing that they are community supported should help minimize this concern.
In addition to describing WebSphere Application Servers as a J2EE implementation product, this book will provide patterns and approaches for neutralizing this dependency.