This appendix describes several design patterns that are used in the main body of the dissertation using a role model form. The patterns are essentially the same as found in their original documentation, except that the role model form portrays them in a different light. The use of role models lets us more flexibly assign role types to classes than the class-based form allows us to do. While the class diagrams of the patterns frequently might look simpler than the role model diagrams, this is not the case. The complexity of a pattern is always the same, independently of its presentation form.
The pattern descriptions in this appendix have the following
properties:
- The descriptions of the patterns are incomplete. They merely
serve as a reminder for those who forgot or do not know a specific
pattern under the given name so they can quickly look it up.
For a more detailed description, references are provided.
- The patterns are illustrated rather than rigidly defined.
There is no design pattern notation behind the pattern descriptions
except than an intuitive understanding about what the role model
illustration might communicate to developers regarding the pattern
instantiation.
- None of the descriptions is to be taken as a rigid definition.
(See the discussion of pattern vs. template in Chapter 3). Role
models are more flexible than class model and suggest a wider
application [Rie96a], but even they cannot encompass all possible
design templates.
In the diagrams, some role types and object relationship descriptions
are grayed out. These role types are required in an instantiation
of a pattern, but are not considered to be an integral part of
the core pattern role model illustration. The primary example
of such a grayed-out role model is the role type pair (Client,
Object) that simply states that an object provides some domain
functionality to a Client.
The Abstract Factory pattern centralizes the creation of objects
from a family of products in a Factory object. A Client requests
new Product objects from a Factory object. The Factory object
ensures consistency among a family of Product objects and hides
the details of the object creation process.
-
- Figure D-1: Role model of the Abstract Factory pattern.
A class-based description of this pattern can be found in [GHJV95].
The Adapter pattern adapts an existing object to a new use-context
by means of an intermediate Adapter object. A Client uses the
Adapter operations only, and the Adapter implements them in terms
of the domain functionality of the Adaptee.
-
- Figure D-2: Role model of the Adapter pattern.
A class-based description of this pattern can be found in [GHJV95].
The Bridge pattern splits the implementation of a domain concept
into an Abstraction and an Implementor object so that both can
be varied independently. The Abstraction provides the primary
domain functionality, and the Implementor provides the implementation
primitives all variations of the Abstraction can be implemented
by. The Client makes use only of the Abstraction. The Abstraction
owns its Implementor, uses its operations for its own implementation,
and hides it from the Client.
-
- Figure D-3: Role model of the Bridge pattern.
A separate Client (not shown in the figure) configures the
Abstraction with its Implementor. A common type of Client is an
Abstract Factory that returns a preconfigured Bridge upon Client
request.
A class-based description of this pattern can be found in [GHJV95].
The Chain of Responsibility pattern determines the target object
of a client request dynamically by passing the request along a
chain of objects. Each object in the chain may decide whether
to execute, drop, or pass on the request. A Predecessor forwards
the request to its Successor.
-
- Figure D-4: Role model of the Chain of Responsibility pattern.
Using an object chain this way lets us configure the recipient
of the request dynamically. A separate client configures the chain
of objects.
A class-based description of this pattern can be found in [GHJV95].
The Class Object pattern provides functionality common to all
objects of a class in one Class object. A Class object can be
asked for meta-information about any of its Instance objects.
In contrast to a Type object, the Class object provides not only
operations to inspect its Instances and provide information about
it, but also functionality to create and change its Instances.
-
- Figure D-5: Role model of the Class Object pattern.
Type Object is one element of the pattern triple Metaobject,
Type Object, and Class Object. The distinction between Class Object
and Type Object is done pragmatically. Class Objects provide implementation
information about its Instances and they can manipulate and create
Instances. Type Objects provide application domain specific information
rather than implementation information; their implementations
may be heterogeneous, and they cannot manipulate their Instances.
To my knowledge, there is no commonly known class-based description
of the pattern. However, any major object-oriented system provides
an implementation of this pattern.
The Composite pattern determines how to build a hierarchy of
objects. Any object in the hierarchy is a Child, or a Parent,
or both. A Child may receive a Parent object, and a Parent object
may receive or drop some Child objects. The Child and Parent role
types serve to configure and maintain the hierarchy. A Client
configures a Parent with its Child objects.
-
- Figure D-6: Role model of the Composite pattern.
A class-based description of this pattern can be found in [GHJV95].
The Decorator pattern lets us transparently add functionality
to an existing object through object composition. A Core object
is wrapped by a Decorator object. The Client makes use of both
the Core and the Decorator without seeing to different objects.
-
- Figure D-7: Role model of the Decorator pattern.
A class-based description of this pattern can be found in [GHJV95].
The Factory Method pattern puts the creation of an object in
method of its own that can be varied independently from the Client
using the method. The Factory Method is provided by a Creator
object that returns a Product object upon Client request.
-
- Figure D-8: Role model of the Factory Method pattern.
A class-based description of this pattern can be found in [GHJV95].
The Manager pattern puts the management of some Elements into
a Manager object so that Element management gets independent of
the Client and the Elements. Clients request Elements from the
Manager. The Manager owns the Elements. It creates, provides,
and deletes them.
-
- Figure D-9: Role model of the Manager pattern.
In [Som98], Sommerlad describes a class-based variant of this
pattern, also called Manager. Sommerlad's Manager requires the
set of Elements to be homogeneous, while the definition of Manager
here accepts a heterogeneous collection of Elements.
The Mediator pattern centralizes the communication of a set
of Colleague objects in one Mediator object. The Colleagues do
not communicate with each other directly, but only through the
Mediator. This reduces communication complexity from square(n)
to n. It facilitates the introduction and removal of a new Colleague
object without affecting the other Colleagues.
-
- Figure D-10: Role model of the Mediator pattern.
A class-based description of this pattern can be found in [GHJV95].
The Metaobject pattern separates the domain-specific functionality
of an object from the technical procedure of executing this domain
functionality. Clients send requests to the Metaobject for execution
on a specific BaseObject. The Metaobject defines the procedures
for executing incoming requests, and the BaseObject provides the
functionality to invoke the domain-specific operations. The Metaobject
typically deals with issues like request queuing and synchronization,
and the BaseObject provides a dynamic invocation interface for
calling the domain-specific operations.
-
- Figure D-11: Role model of the Metaobject pattern.
The configuration of the Metaobject can be complex (see Chapter
6 for an example). Metaobjects are part of a metalevel architecture
that represents the overall (conceptual and/or technical) framework
for handling metalevel issues.
Metaobject is one of the pattern triple Metaobject, Type Object,
and Class Object.
To my knowledge, there is no commonly known class-based description
of the pattern. However, every object-oriented system based on
an explicit metalevel architecture is likely to feature an instance
of this pattern.
The Null Object pattern serves to provide a null implementation
of a domain concept. The null implementation provides null behavior,
which is the behavior assumed to be executed if no object were
present at all. The pattern lets developers set an object reference
to the null object rather than to a null reference and avoids
cluttering the client code with checks whether the reference is
null or not.
-
- Figure D-12: Role model of the Null Object pattern.
In [Woo98], Woolf describes the Null Object pattern. Because
it is only about implementation, the pattern cannot be expressed
well using role modeling.
The Object Registry pattern centralizes access to a set of
Element objects in one Registry object. Clients register and unregister
Elements at the Registry giving them convenient names for later
retrieval. Such a Registry is typically a thread-local or process-local
Singleton.
-
- Figure D-13: Role model of the Object Registry pattern.
The Object Registry pattern is to be distinguished from the
Value Registry pattern (not documented here). An Object Registry
handles objects, and a Value Registry handles values. Clients
of an Object Registry have to be aware of possible side-effects,
while clients of a Value Registry do not have to do so.
The Observer pattern decouples a set of Observers from a Subject.
It is used to maintain state dependencies between the Observers
and their Subject. In case of a state change, the Subject sends
out an event to notify its Observers about the change. The Subject
does not rely on any specific type of Observer, but uses a common
and minimal Observer protocol only. A Client configures the Subject
with its Observers (Client and Observer object may well be the
same).
-
- Figure D-14: Role model of the Observer pattern.
In Java, the Observer pattern takes on the form of EventListeners.
A class-based description of this pattern can be found in [GHJV95].
The Product Trader pattern separates the creation of a Product
object from the Client requesting it by putting the creation process
into a Trader object. Clients request new Products from the Trader
using a specification of the Product (rather than naming its class).
The Trader uses the specification to select an element from a
set of Elements. Each of the Elements can act as a Creator for
the Product.
When asked for a Product, the Trader selects an Element based
on the specification provided by the Client. The Trader then acts
as a Client of the Element that acts as the Creator for the new
Product object. The Trader/Client object asks the Element/Creator
object for a new Product, which is then returned to the Client.
-
- Figure D-15: Role model of the Product Trader pattern.
In [BR98], Bäumer and Riehle present a class-based description
of this pattern.
The Property List pattern makes a Provider object provide a
generic and extensible set of Properties to Clients. A Client
asks a Provider object about its Properties. Properties are accessed
using a naming scheme, for example simple strings, and generic
get and set operations rather than through property-specific operations.
The Provider defines which Properties it offers. Every implementation
of a Provider may provide its own set of Properties. Properties
may even be added and removed at runtime.
-
- Figure D-16: Role model of the Property List pattern.
In [Rie97a], Riehle describes the pattern in more detail using
role modeling.
The Prototype pattern lets Clients create complex Product objects
by cloning a Prototype object. Products are copies of the Prototype
and reflect its possibly complex object configuration. Clients
request a copy of the Prototype, which they receive as a new Product
object. Prototypes serve as representatives of one or several
complex objects and can be handled generically.
-
- Figure D-17: Role model of the Prototype pattern.
A class-based description of this pattern can be found in [GHJV95].
The Role Object pattern transparently attaches Role objects
to a Core object. The Core represents an important domain concept,
and the Roles represent some domain-specific extension of the
Core concept. Clients make use both of the Roles and the Core.
The Core manages its Roles and provides them to a Client upon
request. Roles may be retrieved from the Core using a simple naming
scheme, for example strings.
-
- Figure D-18: Role model of the Role Object pattern.
The Core may be configured with Role objects in many different
ways, for example during configuration time from configuration
data or during execution time through dedicated clients.
In [BRSW00], Bäumer et al. present a class-based description
of this pattern.
The Type Object pattern centralizes common information about
a set of Instance objects in a Type Object that is shared by all
Instances. Clients ask the Type Object of an Instance for information
about the Instance. This information may also be directly provided
by an Instance, but it will be implemented then by asking the
Type Object. Using Type Objects, otherwise redundant information
about common properties of all Instances is provided in a single
place, the Type Object.
-
- Figure D-19: Role model of the Type Object pattern.
Type Object is one of the pattern triple Metaobject, Type Object,
and Class Object. The distinction between Class Object and Type
Object is done pragmatically. Class Objects provide implementation
information about its Instances and they can manipulate and create
Instances. Type Objects provide application domain specific information
rather than implementation information; their implementations
may be heterogeneous, and they cannot manipulate their Instances.
In [JW98], Johnson and Woolf present a class-based description
of this pattern.
The Serializer pattern reads Readable objects from a Reader
and writes Writable objects to a Writer. The Reader reads the
object information from a specific backend, and the Writer writes
the object information to a specific backend. Backends vary with
Reader/Writer implementations. The Serializer pattern is used
to serialize objects for different purposes like making them persistent,
marshalling and unmarshalling them, and debugging them.
Readable and Reader as well as Writable and Writer objects
collaborate recursively. A Readable reads all of its attributes
from a Reader. For attributes that are Readable object references,
the Reader to creates the Readable and then tells it to read its
attributes from it, the Reader. Similarly, a Writable writes its
attributes to a Writer that in turn tells a Writable attribute
to write its attributs on it, the Writer. Primitive value types
like integer and string attributes end the recursive descent.
-
- Figure D-20: Role model of the Serializer pattern.
The Serializer pattern can be viewed as the repeated specialized
composition of the Visitor pattern.
In [RSB+98], Riehle et al. present a class-based description
of this pattern.
The Singleton pattern serves to ensure that there is exactly
one instance of an object, the Singleton, in a given operation
context, and to provide a central convenient access point to it.
Historically, the operation context is the process, but it could
be a thread as well. A Client requests the Singleton from a Provider.
If necessary, the Provider creates the Singleton on demand.
-
- Figure D-21: Role model of the Singleton pattern.
Because the combination of an applied Singleton role model
with an object creation role model of Client, Creator, and Product
role types ocurrs frequently, the dissertation uses a shortcut
for it.
-
- Figure D-22: Shortcut role model of the Singleton pattern.
A class-based description of this pattern can be found in [GHJV95].
The Specification pattern provides descriptive elements about
an object to a client for use in object selection based on specifications.
A Client requests a Specification from a Provider. The Specification
describes one or several properties of the Provider. Typically,
the Specification can provide a unique key to a client that is
computed based on the properties described by the Specification
and that distinguishes the Specification from Specifications of
other Providers.
-
- Figure D-23: Role model of the Specification pattern.
In [Rie96c], Riehle describes the use of the Specification
pattern in the context of class selection and object creation
(also known as trading), and in [EF97], Evans and Fowler describe
several patterns that show how to define and compose complex specifications.
The State pattern serves to split a large state space of an
object into several distinct parts to ease the object's implementation,
to manage the state space more easily, and to extend it more easily.
An Object providing domain functionality to a Client acts as the
Context for a set of State objects. The Context forwards Client
requests to one State object, which implements the requested behavior.
At any given time, exactly one State object is active, representing
the subspace of the overall state space of the object the current
state vector is in. If state changing operations cause the state
vector to leave the current subspace, another State object becomes
active, representing the correct subspace. A State object implements
the behavior according to the rules of the subspace it represents.
-
- Figure D-24: Role model of the State pattern.
A class-based description of this pattern can be found in [GHJV95].
The Strategy pattern serves to configure a domain object with
an instance from a family of algorithms, rather than hard-coding
any specific algorithm in the domain object. The Strategy object
encapsulates the algorithm, and is set to its Context by a Client.
Whenever the domain object has to execute the algorithm it acts
as the Context of the Strategy and delegates the task of performing
the algorithm to it.
-
- Figure D-25: Role model of the Strategy pattern.
A class-based description of this pattern can be found in [GHJV95].
The Visitor pattern serves to extend an existing object structure
with new external algorithms. The different object types from
the structure are represented as different Node role types. Common
to all objects is the Element role type. A Visitor object represents
a new external algorithm. For each of its Node type attributes,
the Element dispatches on a Visitor for the particular Node type.
The Visitor can then execute the behavior associated with that
particular Node type.
Because Node objects can always act as Elements, a Visitor
may recursively descent into the object structure (if it is a
hierarchy). An Element dispatches on an a Visitor for a given
Node type attribute, and the Visitor calls on the Node type attribute
to dispatch back to the Visitor on the Node type's attributes.
Primitive value types and objects that are not Elements end the
recursive descent.
-
- Figure D-26: Role model of the Visitor pattern.
A class-based description of this pattern can be found in [GHJV95].
|