Introduction to Software Patterns
(based on the Design
- What is a good design?
- Tricks of the trade
- Example of a pattern
- Pattern form
- Benefits of patterns
Human to computer: I've got this particular programming problem. My
initial attempts to solve it have resulted in monolithic classes which
don't support several useful cases and are hard to modify. Please show me
successful programs where this problem has occurred, the solution taken,
and the consequences of each.
Software patterns are a first step in realizing this dream. By documenting
the essential technique and rationale behind recurring expert designs, they
help people reuse successful practices.
The purpose of this course is to make you a better software designer.
Design, for our purposes, is determining what kinds of objects should go
into the system and what compile-time and run-time relationships they
should have. This includes the granularity of objects, inheritance
structure, compositional structure, and hooks for extensibility.
What is a good design?
Besides achieving its functional objectives, a good design should decompose
the system into loosely-coupled components with clearly demarcated
variabilities. Despite the hype, object-oriented software is not
arbitrarily adaptable; adaptability is precisely determined by the system's
design. Changing software in unplanned ways will almost surely break it.
Furthermore, undocumented variabilities tend to disappear after a careless
enhancement or bug fix.
Tricks of the trade
Design is a creative process. Formal methods can empower the creative
mind, but they do not fuel creativity. Therefore, unlike most literature
on design, we won't be talking about formal methods, like the Yourdon
method or Booch notation. We will be talking about the tricks of the
trade: what expert designers know that allows them to dream up world-class
What is it that they know? Successful design patterns. Experts reuse
time-worn solutions. Until recently, no record of these solutions was ever
made, partly because the techniques aren't new (they're recurring patterns)
and partly because they are hard to describe. Design patterns are
amorphous and intangible. They are not simply pieces of code or
box-and-arrow diagrams. Hence, they are not captured by macros, class
libraries, or formal notations.
Example of a pattern
Microsoft Foundation Classes (MFC) is a class library for building
applications under Windows. Its basic metaphor is visually editing a
"document," which could be a letter, spreadsheet, database, drawing, graph,
etc. Any subclass of the Document class will do. The visual
representation is provided by an object whose type is a subclass of
MFC uses separate objects for documents and views, rather than lumping them
together. The job of the view object is to ensure that its appearance
reflects the state of the document object. MFC does this via a
subscribe/notify protocol between the document and view. At run-time, each
view object subscribes to a particular document object, and each document
object notifies its subscribers whenever it changes. In response, each
subscribed view gets an opportunity to update itself. This lets you
dynamically attach and detach views of a document. It also allows
multiple, consistent views of the same document.
For example, you might have a document which is an array of numbers. It
can be simultaneously displayed as a spreadsheet, a bar chart, and pie
chart. Modifying the bar chart, say by dragging the height of a bar, will
modify the array, which will then notify the other views and let them
update themselves to match.
This design decouples documents from views, and is indeed a pattern among
modern user interface toolkits. However, this design is useful whenever
you want to decouple an object from the many possible objects dependent on
it. For this reason, it is also a recurring pattern in programming
languages, graphics packages, and distributed databases.
How can we concisely describe and yet generalize this design? The idea,
started by architect Christopher Alexander, is to fill out a form like
- The general problem to be solved. When to apply the pattern.
- Potential consequences that a good solution must take into account.
Forces are often non-functional, such as reducing coupling or providing a
- Objects that make up the design, their roles, and their relationships.
What each object needs to know about the others.
- The costs and benefits of applying the pattern. How well it resolves
the Forces. Used for evaluating competing solutions.
- Suggestions and pitfalls in implementing the pattern.
- Known Uses
- Examples of the pattern found in real systems.
MFC's Document/View architecture, in pattern form, is called the Observer pattern.
Benefits of patterns
By definition, patterns capture experience, so in a sense they aren't new.
However, I hope you can see why patterns are a useful subject of study.
Three benefits of putting recurring designs into pattern form are:
- Learning about design
Surveying the possible designs enlarges your toolbox and fuels creativity.
(This is why the course will also include detailed case studies of real
systems.) Studying a pattern and exploring the implementation alternatives
allows improving the pattern and makes it easier to come up with new
You're now able to take a fairly complex arrangement of interfaces and
run-time interactions between Documents and Views and simplify it to
"Observer pattern." This means you'll be able to conceive of bigger and
better designs, because of the higher level of abstraction. Furthermore,
you'll be automatically reusing techniques that many others have already
tested for you.
- Documenting policy
You can use patterns as documentation, to ensure that components stay
decoupled and variabilities remain flexible. When someone presents you
with code described as being based on the Observer pattern, you can
immediately answer questions about policy, e.g.
Should it be easy to add a new kind of document?
Should the document skip notifying a view if it knows the change won't
affect the display?
Another example of policy is specifying whether one object
contains another vs. simply being acquainted with
another. Both containment and acquaintance can be implemented in the same
way, using pointers or references. But they entail significantly different
policies with respect to the destruction, archival, or
transmission of the object holding the pointer.
Computer to human: You have an object with possibly many dependent
objects that could be reused separately. As you can see, MFC, ET++,
Smalltalk, CORBA, ActiveX, and Inventor have all used variants of the
Observer pattern in this situation...
Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.
Design Patterns: Elements of Reusable Object-Oriented
Software. Addison-Wesley, Reading, MA, 1994.
"Software Patterns" in Communications of the ACM,
Mickey Williams and David Hamilton. Programming Windows NT 4.
Sams Publishing, 1996.
Last modified: Mon Nov 3 20:04:38 EST 1997