Design Patterns
Rarely is a significant problem solved by a single class,
or a small set of classes. Rather, modern software is a
complex interconnected network of objects.
As more OO systems are developed, we have noticed that over and over
similar architectures arise. This is not surprising... software
solves problems in established domains, and it is reasonable for
two different systems that are operating to solve the same problem
might have similar internal structure (assuming both are "good"
designs).
Researchers have started collecting these abstract, common
architectural chunks and are calling them design patterns.
A design pattern is a collection of objects (classes) that
have the functionality and internconnectivity specific to
solving a general problem.
The classes in a design pattern
work together to produce the solution.
A pattern serves as a guide for
creating a "good" design for a new system.
Varieties of Classes
- data managers
responsible for maintaining state information for a computation
(a database, for example)
- data sinks or sources
generate data (random number generator)
does not hold the data, just creates or disposes-of/maniplates it
- view or observer classes
display of information (stored in data manager), specialized
for some display device or specialized by some rendering
techniques
- facilitator or helper classes
assist in the execution of some complex task; maintain little or
no data of their own; in a card game, we might display a
card image on the screen using classes for drawing lines or text;
we might manage the deck with a class that does linked lists.
Application Frameworks
Let's draw a distinction between patterns and frameworks.
A framework is a set of specific classes that cooperate closely with
each other, making a reusable design for solving a general category of
problems. A framework is usually discussed as being implemented
for a specific platform. MVC as implemented in Smalltalk is a framework.
Xtk is a framework; CORBA is a framework; Java Beans is a framework.
A developer customizes a framework to a particular application
by subclassing and composing instances
of framework classes.
A pattern is more abstract, taking on different specific forms for
different platforms. Two different frameworks might both be
based on one design pattern.
A pattern is therefore less specalized; a framework is
specific to a particular application domain.
Frameworks can be embodied in code, they are concrete.
Only examples, instances of a pattern can be embodied in code.
Frameworks are bigger than patterns. They are composed (ideally)
from a collection of instances of patterns.
A framework is executable software; a design pattern is
captured experience (knowledge?) about software.
Design Patterns
Here are various definitions of patterns:
- A pattern is the abstraction from a concrete form which keeps
recurring in specific non-arbitrary contexts.
(Riehle and Zullighoven)
- A pattern is a named nugget of instructive information that
captures the essential structure and insight of a successful family
of proven solutions to a recurring problem that arises within a
certain context and system of forces.
(B. Appleton)
- A pattern is a named nugget of insight that conveys the
essence of a proven solution to a
recurring problem within a certain context amidst competing concerns.
(B. Appleton)
- Each pattern is a 3-part rule, which expresses a relation
between [sic] a certain context, a certain system of forces which
occurs repeatedly in that context, and a certain software
configuration which allows these forces to resolve themselves.
(R. Gabriel)
-
Each pattern is a three-part rule, which expresses a relation between
a certain context, a problem, and a solution.
As an element in the world, each pattern is a relationship between a
certain context, a certain system of forces which occurs repeatedly in
that context, and a certain spatial configuration which allows
these forces to resolve themselves.
As an element of language, a pattern is an instruction, which shows how
this spatial configuration can be used, over and over again, to resolve
the given system of forces, wherever the context makes it relevant.
The pattern is, in short, at the same time a thing, which happens in
the world, and the rule which tells us how to create that thing, and
when we must create it. It is both a process and a thing; both a
description of a thing which is alive, and a description of the
process which will generate that thing.
(C. Alexander)
-
I like to relate this definition to dress patterns. I could tell you
how to make a dress by specifying the route of a scissors through a
piece of cloth in terms of angles and lengths of cut. Or, I could give
you a pattern. Reading the specification, you would have no idea what
was being built or if you had built the right thing when you were
finished. The pattern foreshadows the product: it is the rule for
making the thing, but it is also, in many respects, the thing itself.
(J. Coplien)
- A pattern involves the general description of a recurring
solution to a recurring problem, repleat with various goals and
constraints.
(B. Appleton)
A good pattern meets these criteria:
- It solves a problem
- It is a proven concept
- The solution is not obvious
- It described a relationship
- It has a significant human component
Inheritance vs. Delegation
Many of the patterns that are popular and useful help you decide when to
use inheritance vs. when to use delegation.
notes
Intermediary patterns
This general pattern performs a standing in place of service.
The pattern consists of a client object, which is
interacting with another object, the intermediary.
The intermediary is apparently providing some service to the
client, but in reality the intermediary is simply acting as
an interface to one or more other objects that are servers.
There are several named flavors of pattern intermediary.
All share the characteristic that the intermediate is rather
lightweight, not doing much complicated computation
or data generation. It mainly exists to gather commands
and farm them out appropriately to servers that can handle them.
- Proxy
In proxy, the intermediary is a transmission agent sending requests
along some pathway like a network. The actual
servicing of the request is handled
by the server at the other end of the network.
The intermediary hides the details of network transmission,
making the transaction seem simple.
In some instances of this pattern, the intermediary might
actually manipulate the data in the messages,
changing their form or structure. The intermediary can
also augment (or filter out) information coming back
from the server before passing it to the client.
- Facade
Here the intermediary selects from more than one possible
server to handle the requests from the client. A network
is not necessarily involved.
The intermediary acts as a focus and obviates the need
for the client (there could be many) to remember the
locations and styles of interactions for each worked/server.
- Translator (Adapter)
The actual work is done by a single server/worker,
but the protocol it uses does not match that used by the
client. Intermediary maps names of messages from client
to names of messages for the server.
- Decorator (Wrapper)
"dynamic subclassing". The intermediary passed traffic from client to
server, but then intercepts the return information and embellishes
it in some way. It might, for example, add a window frame and
sliders to the plain text generated by the server/worker.
Decorators can be added at runtime.
- Bridge (State)
Intermediary defines the interface for a task but not the
specifics of an implementation. It can send requests from
the client to several different implementations of the
interface, selecting based on performance issues,
system conditions, etc.
Traversal patterns
When data values are organized into composite structures
you often need to traverse the data structure processes each
value is some way.
Uses of these patterns vary in the processing task for each
node, the form of data in the nodes, the regularity of the
data structure, etc.
- Visitor
Nodes are all the same (homogeneity). Several different types
of visitation might need to happen, though (e.g., in a binary tree
you might be printing in some order, or you might be adding a new
node). The visitor superclass must understand
the data structure, and it will have a virtual method "action".
Each visitor class must subclass this and supply the appropriate action.
- Interpretor
Superficially similar to visitor, the interpreter
pattern involves a data structure where the form is not
regular.
The nodes might each be different in content,
or the linkages among nodes might be unpredictable
or variable.
Example: abstract syntax tree.
Here the action to be performed is encoded in the
data structure class rather than the visitor. A
Visitor will then bring some input to the data structure,
and the data structure will act on it.
- Iterator
This pattern solves the problem of visitor that the visitor class
must know the structure of the data class.
The iterator class knows the data structure and does a
traversal. It passed nodes one at a time to the
client visitor. The action to be performed in
still known to the client/visitor, not to the data or the iterator.
Combining patterns: Model-View-Controller
Often called a paradigm, MVC is a specific arrangement of
three varieties of classes for presenting a user interface.
Before MVC, user interfaces were built so that the three
functions in MVC were mingled and indistinguishable as
components of the solution. MVC defines them as recognizable
objects, each with well-defined tasks.
Model is a data manager class.
It implements the application class, the basic functionality
of the system. It might be something like a simulation,
a database, an editor, etc.
View is an observer class.
It presents some representation of the data in the model.
Controller is a data sink class.
It defines the way the user interface reacts to user input.
One nice aspect of the separation in MVC is that different
views can be imposed on one model. That way, different users
with different needs can have specialized presentations without
disturbing the implementation of the model itself.
Similarly, different controllers (with ot without multiple views)
can be applied to a model. In this way, users in a multi-user
system can specify varying levels of local vs. remote
processing. For example, in a editor, a user might specify
through the controller that information is not transmitted
to the model except on ; alternately, each character typed
might be transmitted to the model; perhaps information is sent
paragraph-by-paragraph... etc.
Some users might prefer pop-up menus for input, others might
like command keys, others text-line input. Different controllers
can accomodate this heterogenity without changing the underlying
application (model) or the presentation (view).
References
-
- "Design Patterns: Elements of Reusable OO Software",
Gamma, Helm, Johnson, and Vlissides (Addison-Wesley, 1995).
- "An Introduction to Object-Oriented Programming,"
T. Budd (Addison-Wesley, 1997).