Warren, who has been programming professionally for four years, can be contacted at tangent@cyberport.com.
Object orientation is great. It promises more reusability, extensibility, and maintainability for your programs than previous paradigms. The problem is, these features don't just accidentally appear in a program, and it's even hard to purposefully program them in. Instead, you must design these features into your program. Design Patterns, and Object-Oriented Design Heuristics will help you to improve and verify your object-oriented designs.
The notion of design patterns is a significant idea that has been making waves in the mainstream development community for a couple of years. A design pattern is a way of documenting a generalized design problem along with its solution and the consequences of using that solution. Another important feature of design patterns is that they have names, allowing them to become part of your vocabulary. Language is a powerful thing, and the size of your vocabulary influences the size of the ideas that you are capable of grasping. In this manner, patterns can help you manage complexity.
Design Patterns: Elements of Reusable Object-oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, begins with a short chapter that explains the basics of design patterns. It also covers pattern notation and introduces the rest of the book.
The next chapter is a case study that explores the design of an object-oriented document editor. The authors use several of the book's patterns to build a flexible design for a program. Like the rest of the book's examples, this one really adds value, because it isn't trivial or contrived. Apparently, the program they describe, called "Lexi," actually exists.
The rest of the book proves the case for the usefulness of patterns with 23 patterns that can enhance almost any design. Reading through these patterns was one of the single most enlightening experiences I've had in my programming career. For one example, this book uses polymorphism in some of the most interesting and truly useful ways that I've ever encountered. Until I read this book, I hadn't progressed much further than the traditional uses of polymorphism, such as the canonical abstract Shape class designed to have derived classes like Circle and Square. Sure, simple hierarchies like these are useful, but they're really only the beginning of the paradigm's usefulness.
One of my favorite patterns of this type is the Composite pattern, which is used to express hierarchical data, but in a much more flexible manner than a standard n-tree. The program from the first part of the book needs a way to describe a "document" that includes text, graphics, and layout elements. Figure 1 , for instance, is an object model that illustrates how to use the Composite pattern to model the document. The notation is based on that presented in James Rumbaugh et al.'s Object Modeling Technique and Design (Prentice Hall, 1991). The model is loosely based on one in the book.
Client is an object that has a reference to a Glyph object. (A glyph is anything that can describe a document.) The Row and Column classes are the Composites in this design because they own other Glyphs-the double arrow indicates "more than one object," and the diamond indicates ownership. So, you could build a document that is a Column that contains many Rows, which in turn contains several Characters.
Let's say that future requirements require that Shape and Table classes be added to the Glyph hierarchy. Since these new classes are Glyphs, the composite classes can contain them just as they held Characters and Rows before. So, you could have documents that have Rows made of some Characters and a Shape; and Columns made of Rows, a Table, and some more Rows.
The true value of any pattern goes beyond any real-world examples. Design patterns capture the essence of a good design in a way that allows designers to reuse it in related applications. However, the authors' choice to illustrate each pattern with a good, real-world example serves to make them provably useful and more understandable.
Each pattern takes up about a dozen pages. The vital parts are the intended applications, structure, and collaborations; you can see each of these parts in the earlier example. Each pattern also includes implementation notes and source code (mostly C++, with some Smalltalk), which document design experience that isn't immediately obvious from the other sections of the pattern. The "Consequences" section documents the positive and negative results of using the pattern; between this and the "Intended Use" section, you can decide if the pattern is applicable to a given problem. The "Known Uses" section is a nice touch that documents uses of the pattern in real-world applications. Finally, each pattern directs you to other, complementary patterns.
Design patterns are all well and fine, argues Arthur Riel in Object-Oriented Design Heuristics, but they're too long to be used for day-to-day designing. Instead, Riel presents 61 short "heuristics" that you can memorize and begin to use reflexively in your designs. A heuristic is similar to a rule ("A class should capture one, and only one, key abstraction."), but isn't intended to be inviolate. Instead, it acts as a guideline that generally indicates the correct way to design something.
This book does for object-oriented design what Scott Meyers' Effective C++: 50 Specific Ways to Improve Your Programs and Designs (Addison-Wesley, 1992) did for C++ programming. In fact, the books are strikingly similar in their presentation. The heuristics are organized by topic, and the logic behind each heuristic is explained in detail. Instead of code, though, Riel uses diagrams to illustrate his points so that the book is language independent. However, Riel does include some C++ examples at the end of the book.
Individually, Riel's heuristics are simple design rules, simply explained, most of which you will quickly agree with. In fact, many or even most of them you've probably heard before. The book is valuable because these heuristics have been collected in one place and justified.
The justifications are important to new designers for obvious reasons. What is interesting is that they are also important to more experienced designers, because these explanations form an informal "Consequences" list similar to that in the Design Patterns book. This is important, because designers often have to make tradeoffs based on conflicting physical and logical design requirements. Also, some of the design heuristics simply don't apply to all situations. So, knowing the consequences of violating a heuristic helps you justify your decision.
Another valuable thing about the book is that Riel doesn't just run down his list of heuristics, explaining them as he goes. He also takes the occasional side-road to cover some related topic. For example, he touches indirectly on Smalltalk's Model-View-Controller architecture while covering the heuristics that govern object-oriented architectures. He even goes a bit further afield sometimes, such as when he discusses the differences between the Booch and Rumbaugh object-oriented design techniques when discussing the association relationship between objects. It is relevant because your choice of methodology can affect the kind of association relationships that you will discover during the design process.
Then, just when you were convinced that Riel is presenting heuristics as direct competitors to design patterns, along comes the tenth chapter, which explains the relationship between design patterns and heuristics. In addition to the expected discussion, Riel transforms a few of his heuristics into effective, useful design patterns.
I can see how you can transform design patterns into heuristics, too, and the exercise reveals something interesting. Heuristics are the little rules that make up good design practice, and patterns are examples of what applying these rules can do for a design. (Both sets of ideas are broader than that, but this is where they intersect.) So, heuristics offer good advice for everyday programming, and patterns offer broader advice-a sort of designer's cookbook.
Both books are excellent, technically and otherwise. Design Patterns is a real eye-opener: If you've ever read a programming book that was just filled with amazing tricks and tips, you'll feel a bit of dj vu with this analogue for designers. The advice in Object-Oriented Design Heuristics will improve your designs and even provoke some thought in other areas. Together they form a powerful tag-team. If you do any object-oriented design at all, you will profit from having both books nearby.
Figure 1:Object model that uses the Composite pattern to model a document.