9.6 Design Patterns


Definition and Structure of a Design Pattern


Once represented, a design may itself be reused by designers other than the original one. Individual designers have always been able to reuse their own designs or those that they had learned about informally from others. However, a broadly understood design representation makes it possible for a designer to communicate well-understood, well-tested designs to other practitioners faced with similar design problems and to students learning about object-oriented design concepts.

A reusable design must include more information than just the design diagrams. Among other things, the problem that the design is meant to address must be defined. This information is important because it allows potential reusers, faced with a particular problems, to identify available designs that are candidates for reuse. Another kind of information that is needed in a reusable design cncerns the trade-offs implied by the design. Typically, designers must achieve a balance between such competing goals as efficiency, flexibility, fault tolerance, and simplicity. A single problem may give rise to several useful designs, each offering a different balance among the design factors.

A design pattern is a proposed format for presenting a reusable design. The structure of a design pattern is defined in the book Design Patterns by Gamma, Helm, Johnson and Vlissides (360) as:

A design pattern systematically names, motivates, and explains a general design that addresses a recurring design problem in object-oriented systems. It describes the problem, the solution, when to apply the solution, and its consequences. It also gives implementation hints and examples. The solution is a general arrangement of objects and classes that solve the problem. The solution is customized and implemented to solve the problem in a particular context.

The first sentence of the definition expresses the intent of a design pattern: to present in a consistent and coherent manner the solution to a recurring design problem. The next two sentences of the definition outline the content of a design pattern. The last two sentences explain the usage of a design pattern. The usage makes clear that a design pattern is not a program or code; it is a design that must be tailored to fit the specific requirements of a particular problem and then implemented. Design Patterns contains a collection of design patterns, one of which is studied in detail here.

A design pattern includes the following twelve elements:

name:
Each pattern has a unique, short descriptive name. The collection of pattern names creates a specialized vocabulary that designers can use to describe and discuss design ideas.
intent:
The intent is a succinct (one-to-three sentence) description of the problem addressed by the design pattern. The intent is useful in browsing design patterns and aids in recalling the purpose of a pattern when the name alone is not a sufficient reminder.
motivation :
The motivation explains a typical, specific problem representative of the broad class of problems that the pattern deals with. It should be clear from the motivation that the problem is widespread and not trivial. The motivation usually includes class diagrams and/or object diagrams along with a textual description.
applicability:
This element is a list of conditions that must be satisfied in order for a pattern to be usable. The conditions express goals that the designer is trying to fulfill (e.g., the ability for clients to be able to ignore the difference between compositions of objects and individual objects), complicating aspects of the problem (e.g., an application uses a large number of objects), and constraints (e.g., storage costs are slight because of the sheer quantity of objects)
.
structure:
A description of the pattern using class diagrams and object diagrams is provided by the structure. The class and object names are generalizations of those that appear in the specific example given in the motivation. For example, the Builder pattern motivation uses an example that has a base class named TextConverter with derived classes ASCIIConverter, TeXConverter, and TextWidgetConverter. The class diagrams in the structure section names the base class Builder and has a single representative derived class named ConcreteBuilder.
participants:
Each class in the structure section is briefly described. The description is a list of each class's responsibilities and purpose in the design.
collaborations:
The important relationships and interactions among the participants are described. Object-interaction diagrams may be used to illustrate complex interaction sequences.
consequences:
This section explains both the positive and negative implications of using the design pattern. Positive implications might be increased flexibility, lower memory usage, easier extensibility, support for particular functionality, or simplified usage. Negative implications might be inefficient behavior in particular cases, complex class structure for certain problems, loss of guarantees of system behavior, or overly general design with attendant loss of performance or storage costs. It is important that authors of design patterns present, and readers of design patterns understand, positive as well as negative consequences. All designs achieve a compromise among many competing forces and no design can avoid have some negative consequences.
implementation:
A representative implementation is shown for the classes given in the structure section. Because the structure section is generalized, so also is the implementation provided in this section. This section is meant as a high-level guide on how to represent the pattern in a given programming language.
sample code:
The essential code for a typical problem (often the one presented in the motivation) is given. This code illustrates in detail how the pattern would be applied to the particular problem.
known uses:
This is a list of systems, libraries, tools, or frameworks that have dealt with the design problem addressed by this design pattern. The example systems may have used a variation of the design pattern as a solution.
related patterns:
Other design patterns that are thought to be useful in combination with this pattern are listed. This list provides additional guidance to designers by offering pointers to other patterns that could potentially help.
 

An Example of a Design Pattern


The Composite pattern, given in Design Patterns, will be used as an example of a design pattern. The name of the pattern is "Composite," suggesting the pattern deals with composing objects. The intent of the pattern is stated as follows:

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and composites of objects uniformly.

The intent expresses both the subject matter of the pattern (trees of objects related by a part-whole relation) as well as the goal of the pattern (uniformity of treatment). The motivation presented for this pattern describes a typical graphical drawing tool that allows users to draw a variety of predefined basic shapes (rectangles, lines, circles, rounded rectangles, polygons, etc.) and also allows shapes to be composed together. A composite shape is treated as a newly defined basic shape in that it can be composed with other basic or composite shapes. A set of operations (draw, move, resize, etc.) can be applied to any shape (basic or composite). Both a class diagram and an object diagram are used to illustrate a design solution. The class diagram is shown in the figure below.



Composite Pattern Example


The applicability section defines two conditions: (1) part-whole hierarchies are being represented, and (2) uniformity of treatment for parts and a whole is sought. The conditions mirror the basic ideas presented in the statement of the pattern's intent. The structure section contains the following generalized class diagram:



Composite Pattern Structure


In the generalized class diagram, the specific kinds of parts are represented by a single class "Leaf," while the class named "Composite" represents a whole. The abstract-base class, "Component," defines an interface that must be implemented by Leaf classes and the Composite class. The abstract-base class reflects the uniform treatment of Leaf and Composite objects. Note also that the generic "Operation" method is an abstraction of some application-specific operation.

The participants section lists the responsibilities of each of the four classes that appear in the structure (Component, Leaf, Composite, Client). For example, the responsibilities of the Composite class are to define the behavior of "a composition of objects, to store the composed (sub)objects, and to implement the operations defined in the abstract base class."

The collaborations section defines how the Composite pattern's participants work together to meet their individual responsibilities and achieve the effect intended for the pattern. For instance, in this example, in the Composite pattern, the client interacts with the Leaf or Composite objects only through the abstract interface defined in the Component class. This collaboration captures a key feature of the pattern: the client is able to manipulate Components without regard for whether they are Leaf class objects or Composite class objects.

Two of the consequences of using the Composite pattern are that it makes it easy to add new kinds of basic components (i.e., Leaf classes) - they are simply added as another class derived from Component - and it can make the design overly general in those cases where only certain combinations of objects have semantic meaning (for example, a document may be viewed as a Composite of paragraphs, tables, sections, etc. However, a correct document must have exactly one title and a table may not have sections within it. It is difficult to enforce these kinds of restrictions with the Composite pattern as the pattern places no limitations on the way in which a Composite can be formed. Notice again that both the strengths and the limitations of the pattern are identified.

The implementation section presents issues relevant to the detailed coding of the classes in the pattern. For example, the trade-off between safety and transparency is considered in this section of the Composite pattern. This trade-off involves where to place the methods for manipulating the children of a Composite. If these methods are placed only in the Composite class, it is safer (because any attempt to apply them to Leaf components is detected as a compile-time error) but it is also less transparent (because Leaf and Composite objects cannot be treated as uniformly as might be desired). Placing the methods in the Component base class yields the opposite trade-off. A compromise strategy introduces a method Composite* Get Composite() in the Component base class. This method is defined in the Leaf derived class to return a null pointer and defined in the Composite derived class to return its this pointer. This strategy minimizes the loss of transparency, as all base class methods apply equally to both Leaf and Composite objects, while it retains a large measure of safety by leaving to the Client the responsibility to differentiation between objects of the two derived classes.

The sample code section gives C++ code for an example of a part-whole problem. This most detailed level of presentation helps to give a concrete representation of the pattern that can be compiled and used for experimentation.

The known uses section lists three application domains (user interface toolkits, a compiler, and financial portfolios) where the pattern has been observed.

Finally, four related patterns are noted, including the Iterator pattern that can be used to traverse composite structures.

Summary

A design pattern is a means of fostering reuse of design knowledge and experience rather than the reuse of a specific implementation. A design pattern falls between a general design heuristic and actual code: it is less general (more limited) than a design heuristic or guideline, which might express, for example, that a class interface should be a coherent and complete set of methods for an abstraction. While heuristics are intended to apply to the broadest range of cases, a design pattern is intended to capture in more detail a single structure or abstraction. At the same time, a design pattern is more general than an implemented class hierarchy or framework. Hierarchies and frameworks are limited in their reuse potential to a single programming language, a single (or small range) of situations, and perhaps even a single operating system or run-time environment. A design pattern, however, has none of these limitations. A design pattern is sufficiently focused to be useful, but general enough to be applicable in a range of applications.

The ultimate value of design patterns will only be realized by an organized, extensive collection of patterns that encompasses generic design problems as well as problems specific to particular applications domains. One might imagine a collection of patterns for real-time systems, distributed/concurrent/parallel applications, and other important application areas. The collection of patterns in Design Patterns is an important beginning.




©1998 Prentice-Hall, Inc.
A Simon & Schuster Company
Upper Saddle River, New Jersey 07458

Legal Statement

 

 

 

ÿ