Chapter 29. Patterns and Frameworks

In this chapter

All well-structured systems are full of patterns. A pattern provides a good solution to a common problem in a given context. A mechanism is a design pattern that applies to a society of classes; a framework is typically an architectural pattern that provides an extensible template for applications within a domain.

You use patterns to specify mechanisms and frameworks that shape the architecture of your system. You make a pattern approachable by clearly identifying the slots, tabs, knobs, and dials that a user of that pattern may adjust to apply the pattern in a particular context.

Getting Started

It's amazing to think of the various ways you can assemble a pile of lumber to build a house. In the hands of a master builder in San Francisco, you might see that pile transformed into a Victorian-style house, complete with a gabled roof line and brightly colored, storybook siding. In the hands of a master builder in Maine, you might see that same pile transformed into saltbox house, with clapboard siding and rectangular shapes throughout.

From the outside, these two houses represent clearly different architectural styles. Every builder, drawing from experience, must choose a style that best meets the needs of his or her customer, and then adapt that style to the customer's wishes and the constraints of the building site and local covenants.

For the inside, each builder must also design the house to solve some common problems. There are only so many proven ways to engineer trusses to support a roof; there are only so many proven ways to design a load-bearing wall that must also handle openings for doors and windows. Every builder must select the appropriate mechanisms that solve these common problems, adapted to an overall architectural style and the constraints of local building codes.

Building a software-intensive system is just like that. Every time you raise your eyes above individual lines of code, you'll find common mechanisms that shape the way you organize your classes and other abstractions. For example, in an event-driven system, using the chain of responsibility design pattern is a common way to organize event handlers. Raise your eyes above the level of these mechanisms and you'll find common frameworks that shape your system's entire architecture. For example, in information systems, using a three-tier architecture is a common way to achieve a clear separation of concerns among the system's user interface, its persistent information, and its business objects and rules.

In the UML, you will typically model design patterns—also called mechanisms—which you can represent as collaborations. Similarly, you will typically model architectural patterns as frameworks, which you can represent as stereotyped packages.

The UML provides a graphical representation for both kinds of patterns, as Figure 29-1 shows.

Mechanisms and Frameworks

Figure 29-1. Mechanisms and Frameworks

Terms and Concepts

A pattern is a common solution to a common problem in a given context. A mechanism is a design pattern that applies to a society of classes. A framework is an architectural pattern that provides an extensible template for applications within a domain.

Patterns and Architecture

Whether you're architecting a new system or evolving an existing one, you never really start from scratch. Rather, experience and convention will lead you to apply common ways to solve common problems. For example, if you are building a user-intensive system, one proven way to organize your abstractions is to use a model-view-controller pattern, in which you clearly separate objects (the model) from their presentation (the view) and the agents that keep the two in sync (the controller). Similarly, if you are building a system for solving cryptograms, one proven way to organize your system is to use a blackboard architecture, which is well-suited to attacking intractable problems in opportunistic ways.

Both of these are examples of patterns—common solutions to common problems in a given context. In all well-structured systems, you'll find lots of patterns at various levels of abstraction. Design patterns specify the structure and behavior of a society of classes, whereas architectural patterns specify the structure and behavior of an entire system.

Patterns are part of the UML simply because patterns are important parts of a developer's vocabulary. By making the patterns in your system explicit, you make your system far more understandable and easier to evolve and maintain. For example, if you are handed a new, raw body of code to extend, you'll struggle for a while trying to figure out how it all fits together. On the other hand, if you are handed that same body of code and told, “These classes collaborate using a publish-and-subscribe mechanism,” you will be a lot further down the path of understanding how it works. The same idea applies to a system as a whole. Saying “This system is organized as a set of pipes and filters” explains a great deal about the system's architecture that would otherwise be difficult to comprehend just by starting at individual classes.

Patterns help you to visualize, specify, construct, and document the artifacts of a software-intensive system. You can forward engineer a system by selecting an appropriate set of patterns and applying them to the abstractions specific to your domain. You can also reverse engineer a system by discovering the patterns it embodies, although that's hardly a perfect process. Even better, when you deliver a system, you can specify the patterns it embodies so that when someone later tries to reuse or adapt that system, its patterns will be clearly manifest.

In practice, there are two kinds of patterns of interest—design patterns and frameworks—and the UML provides a means of modeling both. When you model either pattern, you'll find that it typically stands alone in the context of some larger package, except for dependency relationships that bind them to other parts of your system.

Mechanisms

A mechanism is just another name for a design pattern that applies to a society of classes. For example, one common design problem you'll encounter in Java is adapting a class that knows how to respond to a certain set of events so that it responds to a slightly different set without altering the original class. A common solution to this problem is the adaptor pattern, a structural design pattern that converts one interface to another. This pattern is so common that it makes sense to name it and then model it so that you can use it anytime you encounter a similar problem.

In modeling, these mechanisms show up in two ways.

First, as shown in the previous figure, a mechanism simply names a set of abstractions that work together to carry out some common and interesting behavior. You model these mechanisms as plain collaborations because they just name a society of classes. Zoom into that collaboration and you'll see its structural aspects (typically rendered as class diagrams) as well as its behavioral aspects (typically rendered as interaction diagrams). Collaborations such as these cut across individual abstractions in the system; a given class will likely be a member of many collaborations.

Second, as shown in Figure 29-2, a mechanism names a template for a set of abstractions that work together to carry out some common and interesting behavior. You model these mechanisms as parameterized collaborations, which are rendered in the UML similar to the way template classes are rendered. Zoom into that collaboration and you'll see its structural and behavioral aspects. Zoom out of the collaboration and you'll see how that pattern applies to your system by binding the template parts of the collaboration to existing abstractions in your system. When you model a mechanism as a parameterized collaboration, you identify the slots, tabs, knobs, and dials you use to adapt that pattern by means of its template parameters. Collaborations such as these may appear repeatedly in your system, bound to different sets of abstractions.

Mechanisms

Figure 29-2. Mechanisms

In this example, the Subject and the Observer classes of the pattern are bound to the concrete classes TaskQueue and SliderBar, respectively.

Note

Deciding to model a mechanism as a plain collaboration versus a parameterized one is straightforward. Use a plain collaboration if all you are doing is naming a specific society of classes in your system that work together; use a template collaboration if you can abstract the essential structural and behavioral aspects of the mechanism in a completely domain-independent way, which you can then bind to your abstractions in a given context.

Frameworks

A framework is an architectural pattern that provides an extensible template for applications within a domain. For example, one common architectural pattern you'll encounter in real time systems is a cyclic executive, which divides time into frames and subframes, during which processing takes place under strict deadlines. Choosing this pattern versus its alternative (an event-driven architecture) colors your entire system. Because this pattern (and its alternative) is so common, it makes sense to name it as a framework.

A framework is bigger than a mechanism. In fact, you can think of a framework as a kind of micro-architecture that encompasses a set of mechanisms that work together to solve a common problem for a common domain. When you specify a framework, you specify the skeleton of an architecture, together with the slots, tabs, knobs, and dials that you expose to users who want to adapt that framework to their own context.

In the UML, you model a framework as a stereotyped package. Zoom inside that package and you'll see mechanisms that live in any of various views of a system's architecture. For example, not only might you find parameterized collaborations, you might also find use cases (which explain how to use the framework) as well as plain collaborations (which provide sets of abstractions that you can build upon—for instance, by subclassing).

Figure 29-3 illustrates such a framework, named CyclicExecutive. Among other things, this framework includes a collaboration (CommonEvents) encompassing a set of event classes, along with a mechanism (EventHandler) for processing these events in a cyclic fashion. A client that builds on this framework (such as Pacemaker) could build on the abstractions in CommonEvents via subclassing and could also apply an instance of the EventHandler mechanism.

Frameworks

Figure 29-3. Frameworks

Note

Frameworks can be distinguished from plain class libraries. A class library contains abstractions that your abstractions instantiate or invoke; a framework contains abstractions that may instantiate or invoke your abstractions. Both of these kinds of connections constitute the framework's slots, tabs, knobs, and dials that you must adjust to adapt the framework to your context.

Common Modeling Techniques

Modeling Design Patterns

One thing for which you'll use patterns is to model a design pattern. When you model a mechanism such as this, you have to take into account its inside as well as its outside view.

When viewed from the outside, a design pattern is rendered as a parameterized collaboration. As a collaboration, a pattern provides a set of abstractions whose structure and behavior work together to carry out some useful function. The collaboration's parameters name the elements that a user of this pattern must bind. This makes the design pattern a template that you use in a particular context by supplying elements that match the template parameters.

When viewed from the inside, a design pattern is simply a collaboration and is rendered with its structural and behavioral parts. Typically, you'll model the inside of this collaboration with a set of class diagrams (for the structural aspect) and a set of interactions (for the behavioral aspect). The collaboration's parameters name certain of these structural elements, which, when the design pattern is bound in a particular context, are instantiated using abstractions from that context.

To model a design pattern,

  • Identify the common solution to the common problem and reify it as a mechanism.

  • Model the mechanism as a collaboration, providing its structural as well as its behavioral aspects.

  • Identify the elements of the design pattern that must be bound to elements in a specific context and render them as parameters to the collaboration.

For example, Figure 29-4 shows a use of the Command design pattern (as discussed in Gamma et al., Design Patterns, Reading, Massachusetts: Addison-Wesley, 1995). As its documentation states, this pattern “encapsulates a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.” As the model indicates, this design pattern has three parameters that, when you apply the pattern, must be bound to elements in a given context. This model shows two such bindings, in which PasteCommand and OpenCommand are bound to separate bindings of the pattern.

Modeling a Design Pattern

Figure 29-4. Modeling a Design Pattern

The parameters are the AbstractCommand, which must be bound to the same abstract superclass in every case; the ConcreteCommand, which is bound to the various specific classes in various bindings; and the Receiver, which is bound to the class on which the command acts. The Command class could be created by the pattern, but making it a parameter permits multiple command hierarchies to be created.

Note that PasteCommand and OpenCommand are both subclasses of the Command class. Very likely, your system will use this pattern a number of times, perhaps with different bindings. The ability to reuse a design pattern like this as a first-class modeling element is what makes developing with patterns so powerful.

To complete your model of a design pattern, you must specify its structural as well as its behavioral parts, which represent the inside of the collaboration.

For example, Figure 29-5 shows a class diagram that represents the structure of this design pattern. Notice how this diagram uses classes that are named as parameters to the pattern. Figure 29-6 shows a sequence diagram that represents the behavior of this design pattern. Note that the diagram is only suggestive of the possibilities; a design pattern is not a rigid thing.

Modeling the Structural Aspect of a Design Pattern

Figure 29-5. Modeling the Structural Aspect of a Design Pattern

Modeling the Behavioral Aspect of a Design Pattern

Figure 29-6. Modeling the Behavioral Aspect of a Design Pattern

Modeling Architectural Patterns

The other thing for which you'll use patterns is to model architectural patterns. When you model such a framework, you are, in effect, modeling the infrastructure of an entire architecture that you plan to reuse and adapt to some context.

A framework is rendered as a stereotyped package. As a package, a framework provides a set of elements, including—but certainly not limited to—classes, interfaces, use cases, components, nodes, collaborations, and even other frameworks. In fact, you'll place in a framework all the abstractions that work together to provide an extensible template for applications within a domain. Some of these elements will be public and represent resources that clients can build on. These are parts of the framework that you can connect to the abstractions in your context. Some of these public elements will be design patterns and represent resources to which clients bind. These are the parts of the framework that you fill in when you bind to the design pattern. Finally, some of these elements will be protected or private and represent encapsulated elements of the framework that are hidden from the outside view.

When you model an architectural pattern, remember that a framework is, in fact, a description of an architecture, albeit one that is incomplete and possibly parameterized. As such, everything you know about modeling a well-structured architecture applies to modeling well-structured frameworks. The best frameworks are not designed in isolation; to do so is an guaranteed way to fail. Rather, the best frameworks are harvested from existing architectures that are proven to work, and the frameworks evolve to find the slots, tabs, knobs, and dials that are necessary and sufficient to make that framework adaptable to other domains.

To model an architectural pattern,

  • Harvest the framework from an existing, proven architecture.

  • Model the framework as a stereotyped package, containing all the elements (and especially the design patterns) that are necessary and sufficient to describe the various views of that framework.

  • Expose the plug-ins, interfaces, and parameters necessary to adapt the framework in the form of design patterns and collaborations. For the most part, this means making it clear to the user of the pattern which classes must be extended, which operations must be implemented, and which signals must be handled.

For example, Figure 29-7 shows a specification of the Blackboard architectural pattern (as discussed in Buschmann et al., Pattern-Oriented Software Architecture, New York, NY: Wiley, 1996). As its documentation states, this pattern “tackles problems that do not have a feasible deterministic solution for the transformation of raw data into high-level data structures.” The heart of this architecture is the Blackboard design pattern, which dictates how KnowledgeSources, a Blackboard, and a Controller collaborate. This framework also includes the design pattern Reasoning engine, which specifies a general mechanism for how each KnowledgeSource is driven. Finally, as the figure shows, this framework exposes one use case, Apply new knowledge sources, which explains to a client how to adapt the framework itself.

Modeling an Architectural Pattern

Figure 29-7. Modeling an Architectural Pattern

Note

In practice, modeling a framework completely is no less a task than modeling a system's architecture completely. In some ways, the task is even harder because to make the framework approachable, you must also expose the slots, tabs, knobs, and dials of the framework, and perhaps even provide meta-use cases (such as Apply new knowledge sources) that explain how to adapt the framework, as well as plain use cases that explain how the framework behaves.

Hints and Tips

When you model patterns in the UML, remember that they work at many levels of abstraction, from individual classes to the shape of the system as a whole. The most interesting kinds of patterns are mechanisms and frameworks. A well-structured pattern

  • Solves a common problem in a common way.

  • Consists of both structural and behavioral aspects.

  • Exposes the slots, tabs, knobs, and dials by which you adapt those aspects to apply them to some context.

  • Is atomic, meaning that it is not easily broken into smaller patterns.

  • Tends to cut across individual abstractions in the system.

When you draw a pattern in the UML,

  • Expose the elements of the pattern that you must adapt in context.

  • Supply use cases for using, as well as adapting, the pattern.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.221.53.209