Dissection of an Application Frameworks, Part 2, Page 4
Gray-box frameworks take both inheritance and composition approach, is usually made up with combination of abstract classes and concrete classes. The approach of enabling its common spots and hot spots is determined on a component-by-component basis. Figure 9 shows a gray-box framework.
Note: Because a concrete class that contains virtual methods can either be used directly or inherited by another class that overrides the virtual methods to alter its behavior, it is possible for a gray-box framework to consist of only concrete classes, as long as the approach taken by the classes is a combination of composition and inheritance.
In the real world, the application frameworks you will be developing will most likely be gray-box frameworks. The decision whether a given components will follow the inheritance approach or composition approach is decided by which approach is best suited for what the component is trying to accomplish and how developers will likely use the component in their business applications.
Figure 9. A gray-box framework
From the performance point of view, the composition approach tends to beslower than the inheritance approach, primarily because of the extra components it has to load and access at run time to produce the desired results. As you are gathering the features from multiple components, you may also add a number of extra calls to bridge different components. In the inheritance approach, however, an inherited class often contains most of the required features within itself, hence reducing the number of objects the program needs to create and access to produce the same results and eliminating as well much of the extra code that would be needed to bridge different components if the composition approach were used.
Maintenance is another area in which we see the tradeoffs in both approaches. In the composition approach, developers work with a set of highly decoupled framework components, which makes their application more adaptive to changes, and hence more flexible and extensible. However, after the application is deployed, those who provide postproduction support will have to deal with many more "moving parts," which leads to extra maintenance effort. For example, a change in a business requirement may result in the modification of framework components. With a composition approach, such requirement changes may potentially affect a series of framework components that participate in a certain business feature, since the business requirement is supported by the collaboration of a number of components. Such changes in multiple components may also multiply the effort in testing and deployment of the application framework. On the other hand, the inheritance approach may be less flexible than the composition approach, but in compensation, it introduces fewer moving parts. When business features are served by a hierarchy of classes, a change in business requirements can often be resolved with changes to far fewer classes on the hierarchical tree. Of course, the real maintenance cost of your application framework depends on the design of the framework as well as the type of business-requirement changes involved. But generally speaking, you have less overhead on maintenance if you have fewer moving parts to deal with.
Usability is yet another area you need to consider in designing the application framework. The framework component that takes on the inheritance approach usually hides the complex coordination logic and process flow inside the parent class or abstract class, so the developer often needs only to implement or override a few methods to achieve the desired result. Hence, inheritance provides very good usability as long as developers aren't required to learn overwhelming details of the parent class or abstract class they inherit. Usability for the composition approach, on the other hand, depends considerably on how much composition developers have to support to achieve certain results. Having a set of highly decoupled components often requires developers to learn and code their own coordination logic and process flow to wire such components together to produce the desired results. However, if you are willing to sacrifice flexibility and create a few coarse-grained components so that developers need to work with only a small number of components to get what they want, then the framework will become easier to use and developers will be much more productive, since the composition approach significantly reduces the coordination logic developers have to learn and write.
As you approach many framework design decisions, you must keep in mind that there is no silver bullet. There is often a tradeoff between different approaches. It is your job to decide how to balance them and create an application framework that fits your objectives.
As you are architecting and developing the application framework, you will often run into design challenges on recurring scenarios, such as how to improve handling of changes to the process flow and how to improve application-specific customization. Design patterns, which describe the solution to common software development problems, can assist you in solving some of these common problems in developing an application framework. Many commonly used design patterns are documented in the classic book Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, the "gang of four" (GOF). Some design patterns are especially useful in application framework development. The following list describes some of these patterns and the problems they can solve:
Strategy: a design that handles the variation of algorithms in the application. It allows the developer to customize the framework by "plug and play"-ing different application-specific algorithms.
Bridge: a design that decouples the abstraction and implementation in the application. It allows developers to provide different implementations for part of the application without affecting other parts of the application.
Decorator: a design that provides a layer approach in processing data. It allows developers to easily assemble multiple components to process data.
Observer: a design that provides a publishsubscribe communication model. It allows developers to disperse information easily to multiple objects.
Mediator: a design that keeps objects from referring to each other explicitly. It allows developers to create loosely coupled communication between different objects.
Template method: a design that provides the skeleton of the algorithm it oper-ates. It allows developers to define process flow and coordination logic without having to define how the algorithm is implemented.
Visitor: a design that lets you define a new operation without changing the existing ones. It allows developers to decouple an operation from the coordination logic that is constantly changing.
Singleton: a design that ensures that only one instance of the class is created. It allows developers to have better control of the creation of the object.
Abstract factory: a design that provides an interface for creating families of objects without specifying their concrete classes. It allows developers to reduce the reference to concrete classes throughout the application, and hence reduce the amount of code changed when the concrete classes change.
For the rest of the book, we will look at how these design patterns can help us develop our application framework and how these patterns are implemented in .NET.
In this chapter, you have learned about processes and techniques of application framework development. We first looked at the different layers that make up the application framework and how each layer is related to the others. Then we looked at the framework development process, which involves analysis, design, development, and stabilization stages in an iterative fashion and specific tasks involved in each of these stages. Following that, you learned about the several approaches in framework development, such as white-box, black-box, and gray-box frameworks. We also looked at some key framework development techniques through discussion of common-spot, hot-spot, and design patterns.
About the Author
Xin Chen is the founder of Xtremework, Inc. Since the inception of .NET, Xin Chen has helped customers in a wide range of industries turn their business ideas into software products using .NET technology. Leveraging his expertise in .NET and EAI, Xin Chen has also worked with several technology leaders, such as Microsoft and Accenture, to bring winning solutions to their customers. When not working overtime, Xin enjoys reading books, writing books, and resting. He is the author of BizTalk 2002 Design and Implementation (Apress, 2003). Xin Chen earned a master's degree in statistics from Columbia University and is currently living in New Jersey.
About the Book
Developing Application Frameworks in .NET by Xin Chen