Wednesday, October 21, 2009

Hierarchical Reuse


3 4



Hierarchical Reuse



The key to making interface implementations reusable is decoupling them from the implementation of particular objects. For example, a developer might recognize the need of a particular object to persist its state. She proceeds to add save and load methods to the object's primary interface. Later she discovers similar objects that have a similar need for persistence. But the save and load implementations she already wrote have become an inseparable part of the first object and are not subject to reuse. A far superior approach is to provide an IPersistStream implementation separate from and outside any particular object but usable by all of them. I am not saying that the path to discovering this need for a separate persistence implementation is unusual or suggests a reckless development practice. Recognizing a need to share and encapsulate a reusable piece often comes from the observation of commonality. However, this discovery should precede the actual writing of code so that isolation of functionality
can be planned and rewrites can be minimized.



Some development systems, Visual Basic being a prominent example, identify coclasses with their default interface. This step is taken for simplicity's sake. The ability to instantiate an object and immediately invoke its behavior through the interface that the object has designated as its most germane is convenient. This saves the step of having to identify the interface through which to address an instance separately from its coclass. However, you should not interpret this convenient mixing of concepts as encouragement to place all an object's behavior into its primary interface. The primary interface is for the subset of behavior that is unique to an object, the subset that it does not share with any other objects. Placing the definition for shared behavior in separate interfaces and then placing shared implementations of such interfaces in separate code modules makes reuse of such software possible.



It might come as a shock to some developers that gathering a set of related functions and packaging them as an object does not constitute good object-oriented practice. In object-oriented analysis and design, the quality of an abstraction is measured by two of its characteristics:




  • Its cohesion. An abstraction is cohesive if it succeeds in succinctly representing a clear concept. All of a class's methods must be directly relevant to this representation.


  • The degree to which it is coupled to related abstractions. If coupling is high, reuse will be low because the abstraction is too intertwined with the rest of the software system to be maintained separately.





Keep these goals in mind when designing interfaces and selecting sites for their implementation. A weak abstraction will never be reused and instead will have its functions reinvented in other places.



Developers use a few criteria to determine the value of a solution for isolating an interface implementation and then reusing it in multiple places. Consider these characteristics:




  • The degree of reusability of the solution. Some solutions might be reusable universally across implementation languages. Others might require implementation environments with certain capabilities. Still others might be source techniques applicable only to a certain language.


  • The amount of work an object has to perform to take advantage of the solution. What steps does an object's developer have to follow to expose the prepackaged interface implementation?


  • The adaptability of the prepackaged interface implementation by the object. Can the object adjust the implementation in ways perhaps not anticipated? How easy is it for the prepackaged interface implementation to invoke functionality a reuser implements to supplement the interface implementation? In other words, can the prepackaged implementation be partially overridden? Can an implementation provide support for methods whose signature will be determined by the objects that will use it?


  • The degree of isolation of the interface implementation. If an interface is altered during development, will objects that expose its prepackaged implementation change as well? What if new versions to interfaces are introduced? Will objects have to change then, or will the prepackaged implementation be capable of adding support for the new interface without requiring adjustments to all the objects that use the implementation?





No comments: