Beautiful Code [292]
Frameworks are active and exhibit "inversion of control" at runtime
Class libraries are typically passive—i.e., they perform isolated bits of processing when invoked by threads of control from self-directed application objects. In contrast, frameworks are active—i.e., they direct the flow of control within an application via event-dispatching patterns, such as Reactor [] and Observer. [] The "inversion of control" in the runtime architecture of a framework is often referred to as "The Hollywood Principle," which states "Don't call us, we'll call you." [§§]
[]Schmidt et al., op. cit.
[] Gamma et al., op. cit.
[§§] "Pattern Hatching - Protection, Part I: The Hollywood Principle," John Vlissides, C++ Report, February 1996.
Frameworks are typically designed by analyzing various potential problems that the framework might address and identifying which parts of each solution are the same and which areas of each solution are unique. This design method is called commonality/variability analysis, [||||]which covers the following topics:
[||||] "Commonality and Variability in Software Engineering." J. Coplien, D. Hoffman, and D. Weiss, IEEE Software, Vol. 15, No. 6, November/December 1998.
Scope
Defines the domains (i.e., the problem areas a framework addresses) and the context of the framework.
Commonalities
Describe the attributes that recur across all members of the family of products based on the framework.
Variabilities
Describe the attributes unique to the different members of the family of products.
26.2.1. Understanding the Commonalities
The first step in designing our logging server framework is therefore to understand the parts of the system that should be implemented by the framework (commonalities) and the parts of the system left to be specialized in subclasses or parameters (variabilities). This analysis is straightforward because the steps involved in processing a log record sent over a network can be decomposed into the steps shown in Figure 26-3, which are common to all logging server implementations.
During this stage of the design process, we define each step as abstractly as possible. For example, at this stage we've made minimal assumptions about the type of IPC mechanisms, other than they are connection-oriented to ensure reliable delivery of log records. Likewise, we've avoided specifying the type of concurrency strategy (e.g., whether the server can handle multiple requests, and if so, how they are dispatched) or the synchronization mechanism used by each step. The actual choice of specific behavior for a step is thus deferred to the subsequent concrete implementations that provide a particular variant for each step.
Figure 26-3. Logging server main loop
The Template Method pattern is a useful way to define abstract steps and defer implementation of their specific behaviors to later steps in the design process. This pattern defines a base class that implements the common—but abstract—steps in the template method in terms of hook methods that can be overridden selectively by concrete implementations. Programming language features, such as pure virtual functions in C++ or abstract methods in Java, can be used to ensure that all concrete implementations define the hook methods. Figure 26-4 shows the structure of the Template Method pattern and demonstrates how this pattern is applied to the design of our OO logging server framework.
Figure 26-4. Template Method pattern and its application to the logging server
26.2.2. Accommodating Variation
Although the Template Method pattern addresses the overall design of the steps in our logging server framework, we're left with the question of how to accommodate all three dimensions of variability defined earlier (IPC, concurrency, and synchronization mechanisms) needed to support our design. One approach would simply use the Template Method pattern and implement one IPC/concurrency/synchronization combination per concrete subclass. Unfortunately, this approach would yield exponential growth in the number of concrete