Book Reviews


Design Patterns, Elements of Reusable Object-Oriented Software

reviewed by George Patapis


George Patapis has been developing software for over ten years, initially as a hobby and now for Telecommunications companies. He graduated with an Honors Degree in Computer Science from Macquarie University, Sydney, Australia in 1991. His areas of expertise and interest are Distributed Systems, Network Management, QAS, and Object-Oriented Software Engineering.

I first heard about the term "Patterns," as used in software development, at a seminar given by Grady Booch back at Object World 1993. Ever since then I wanted to learn more about patterns but it wasn't until the release of this book that I had a chance to fully appreciate the concept and gain a better understanding of it.

The authors identify this as a book of "design patterns that describe simple and elegant solutions to specific problems in object-oriented software design." If you have ever wondered how you can use OO to create programs that are more resilient to change, more modular, and more pleasing to the eye, then this book could be for you.

Book Contents

The first chapter of this book is an introduction to design patterns. Rather than provide an abstract definition for patterns, I let the patterns' overall form speak for itself: a pattern is identified by its name, the problem it tackles, the solution it offers, and the consequences of applying the pattern. The book uses a common structure to describe each pattern, composed of the following headings: Pattern Name and Classification, Intent, Also Known As, Motivation, Applicability, Structure, Participants, Collaborations, Consequences, Implementation, Sample Code, and Known Uses and Related Patterns. To depict the object and class relationships, the authors use Rumbaugh's OMT style notation. (A summary of OMT notation appears in a separate section of the book; a reference also appears on the back cover.)

The first chapter also contains a catalog of the patterns, a section on how design patterns solve design problems, and tips on selecting and using a pattern.

The second chapter is a case study, built around the design of a document editor. The case study covers several of the cataloged patterns. Encountering fleshed-out examples so quickly is a bit like being thrown into the deep end and learning how to swim — which I didn't mind in the least. This case study also helps introduce the rest of the design pattern examples, the vast majority of which seem to have stemmed out of GUI development. It's no surprise that so many of these patterns originated in GUIs, considering how much effort the industry has poured into producing applications that are GUI-independent, or GUI frameworks that are platform-independent. Whatever their origin, the patterns can be applied to other software segments; I felt a bit let down that the GUI bias robbed attention from other areas, such as Telecommunications applications. Maybe it's time we start creating and documenting some of those too!

Chapter three onwards comprise a more elaborate version of the Design Pattern Catalog. This catalog consists of three main groups of patterns, organized according to function. They are summarized as follows:

The book makes a further distinction between patterns that apply to classes which are static and primarily use inheritance to establish relationships, and patterns that apply to objects which are more dynamic and can establish relationships dynamically (at run time). Most patterns fall into the latter category.

Since all following chapters except the last go through each pattern, I present a quick run-down on them and use the examples where convenient.

Creational Patterns

The Creational Patterns include the following:

Abstract Factory. Think of a GUI Toolkit that needs to support multiple look-and-feel standards. Abstract the widgets needed and hide the concrete widget classes from the client. Each collection of a concrete widget class then supports a specific look-and-feel standard but the user of the Toolkit always accesses it through the same common interface.

Builder. Consider a program that parses Rich Text Files (RTF) and must save them in many different formats (e.g. ASCII Text, TeX Text). The Builder pattern separates the mechanics of parsing (reading) the RTF, from the algorithms of creating and building new representations (ASCII, TeX).

Factory Method. Define an interface for the creation of an object but let subclasses decide which class to instantiate.

Prototype. Specify the kinds of objects to create by using a prototypical instance, and create new objects by copying this prototype.

Singleton. For systems that contain a class that can have exactly one instance (e.g. a printer spooler), make that class responsible for keeping track of its sole instance.

Structural Patterns

Adapter. If a class's interface is not exactly what a client expects, use either inheritance or object composition with the old class interface to provide a new interface that meets client expectations.

Bridge: Decouple an abstraction from its implementation. This allows the two class hierarchies to vary independently.

Composite. Compose objects into tree structures to represent part-whole hierarchies. Clients use individual objects and compositions of objects in exactly the same manner.

Decorator. Suppose you have a user interface toolkit and you wish to make a scrolling feature available to your components, rather than subclassing and making it available to all classes. To implement the Decorater pattern extend functionality by encapsulating this feature in a new object called decorator to provide the new functionality when required.

Facade. If you break a large system up into subsystems, provide one class that becomes the interface to a subsystem, thus hiding all internal complexity. This object becomes the facade!

Flyweight. The Flyweight pattern specifies a way of reusing objects, to save space by separating the state-dependent and state-independent parts of an object.

Proxy. Suppose you have a document editor and within it, resource-hungry bitmapped images may be included. You do not want to instantiate such objects unnecessarily because of resource considerations (it may take several seconds for each image to appear when you bring up a document). Use a placeholder, or proxy object which will instantiate and make the image available if and when required.

Behavioral Patterns

Chain Of Responsibility. This pattern is used to decouple sender and receiver objects. A message arrives and gets passed from object to object until it reaches the object meant to handle it.

Command. Encapsulate requests to objects as an object in their own right. This pattern is useful for building history lists of operations, enabling, for example, undo facilities in applications.

Interpreter. This looks to me like a an OO way of doing what lex and yacc do.

Iterator. This is a well-known approach to traversing elements of an aggregate object (list, queue etc.) without exposing its underlying implementation mechanisms.

Mediator. If you need a lot of objects in your system to implement the system's behavior, then a mediator object can act as a "one stop shop" for all the objects. All the objects go through the mediator rather than having to know about and interact with all their peer objects. The mediator pattern thus reduces coupling.

Memento. This pattern provides a way to save an object's state information.

Observer. Suppose you have a GUI that is representing some of your database data with multiple views, such as a spreadsheet view, a pie chart view, and a bar chart view. Each view is an observer of the data, which is the subject. The observers register to the subject that they would like to be notified of any changes to it. When one observer changes the data, the subject then notifies the other interested observers.

State. Represent the different states of an object as objects in their own right. Provide one interface to the outside world but allow each state object to implement its relevant behavior.

Strategy. Encapsulate algorithms into a class, all sharing the same interface. Let clients pick the algorithm to use.

Template. Allow subclasses to implement parts of an algorithm in an operation.

Visitor. If you have a large object structure and different kinds of operations must be applied to the parts of this structure, encapsulate these operations in Visitor objects which execute the operations for each object member of the structure.

Chapter 6 concludes the book with some history on patterns and on the process which lead to the writing of the book.

What Patterns Mean

In order of increasing complexity, here is where I place patterns in relation to other software constructs: algorithms, idioms, design patterns, frameworks. In fact, this book often references idioms as presented in James Coplien's book, Advanced C++ Programming Styles and Idioms [1] (makes me want to go back and also read James's book!).

My favorite patterns include singleton, facade, observer, and state. They are not particularly complex but I have had need of them on many occasions. They appear simple to implement and cross many application domain boundaries.

Audience, Uses For Book

This book is for the experienced developer. You'll want plenty of exposure to software design and architecture before tackling this book, and the more C++ you know, the better! I always learn more from studying examples; this book accompanies each pattern with sample code, and most of it is in C++ (and not the elementary stuff). A bit of Smalltalk appears here and there as well.

The authors derive all patterns from real-world applications. After reading this book you cannot help feeling more knowledgable and appreciative of Object Oriented Design.

This is not a very long book, approximately 400 pages, unfortunately. I say unfortunately because the Software Engineering field needs more such documented patterns on which future developers can build. This book makes a good start but I hope to see many more volumes added.

I find the book well organized, and after reading it the first time through I can now use it as a valuable reference. (The front cover shows a summary of the patterns together with their page number in the book.)

I do not do justice to the patterns with my very quick reference as presented earlier. I hope though, that my brief reference will entice you to read this book and add it to your collection. Even if you find only one useful pattern it can save you hours of effort and cover the cost of buying the book.

Reference

[1] James Coplien. Advanced C++ Programming Styles and Idioms (Addison-Wesley, 1991).

Title: Design Patterns, Elements of Reusable Object-Oriented Software
Authors: Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides.
Publisher: Addison-Wesley
Price: $39.76
Pages: 416
ISBN: 0-201-63361-2