Chapter 1. Introduction

Sitting at your desk in front of your workstation, you stare into space, trying to figure out how to write a new program feature. You know intuitively what must be done and what data and which objects come into play, but you have this underlying feeling that there is a more elegant and general way to write this program.

In fact, you probably don't write any code until you can build a picture in your mind of what code does and how the pieces of the code interact. The more that you can picture this "organic whole" or gestalt, the more likely you are to feel comfortable that you have developed the best solution to the problem. If you don't grasp this whole right away, you might stare out of the window for a long time, even though the basic solution to the problem is quite obvious.

In one sense, you feel that the more elegant solution will be more reusable and more maintainable. However, even if you are likely to be the only programmer, you feel reassured once you have designed a solution that is relatively clean and doesn't expose too many internal inelegancies.

One of the main reasons that computer science researchers began to recognize design patterns was to satisfy this need for good, simple, and reusable solutions. The term design pattern sounds a bit formal to the uninitiated and can be somewhat off-putting when you first encounter it. But, in fact, a design pattern is just a convenient way of reusing object-oriented (OO) code between projects and between programmers. The idea behind design patterns is simple: to catalog common interactions between objects that programmers have often found useful.

A common pattern cited in early literature on programming frameworks is Model-View-Controller (MVC) for Smalltalk [Krasner and Pope, 1988], which divides the user interface problem into three parts (see Figure 1.1):

The Model-View-Controller framework.

Figure 1.1. The Model-View-Controller framework.

  • Data Model, which contains the computational parts of the program

  • View, which presents the user interface

  • Controller, which interacts between the user and the view

Each aspect of the problem is a separate object, and each has its own rules for managing its data. Communication between the user, the graphical user interface (GUI), and the data should be carefully controlled; this separation of functions accomplishes that very nicely. Three objects talking to each other using this restrained set of connections is an example of a powerful design pattern.

In other words, a design pattern describes how objects communicate without becoming entangled in each other's data models and methods. Keeping this separation has always been an objective of good OO programming. If you have been trying to keep objects minding their own business, you are probably already using some of the common design patterns. It is interesting that the MVC pattern is used throughout Java 1.2 as part of the JFC, also known as Swing components.

More formal recognition of design patterns began in the early 1990s when Erich Gamma [1993] described patterns incorporated in the GUI application framework, ET++. Programmers began to meet and discuss these ideas. The culmination of these discussions and a number of technical meetings was the publication of the seminal book, Design Patterns—Elements of Reusable Software, by Gamma, Helm, Johnson, and Vlissides [1995]. This book, commonly called the Gang of Four, or GoF, book, became an all-time bestseller and has had a powerful impact on those seeking to understand how to use design patterns. It describes 23 common, generally useful patterns and comments on how and when you might apply them. We will refer to this groundbreaking book as Design Patterns, throughout this book.

Since the publication of Design Patterns, several other useful books have been published. One closely related book is The Design Patterns Small talk Companion [Alpert, Brown, and Woolf, 1998], which covers the same 23 patterns but from the Smalltalk point of view. In this book, we refer to it as the Smalltalk Companion.

Defining Design Patterns

We all talk about the way that we do things in our everyday work, hobbies, and home life and recognize repeating patterns all the time.

  • Sticky buns are like dinner rolls, but I add brown sugar and nut filling to them.

  • Her front garden is like mine, except that in mine I use astilbe.

  • This end table is constructed like that one, but in this one, the doors replace drawers.

We see the same thing in programming when we tell a colleague how we accomplish a tricky bit of programming so that the colleague doesn't have to recreate it from scratch. We simply recognize effective ways for objects to communicate while maintaining their own separate existences.

Some useful definitions of design patterns have emerged as the literature in this field has expanded.

  • "Design patterns are recurring solutions to design problems you see over and over." [Smalltalk Companion]

  • "Design patterns constitute a set of rules describing how to accomplish certain tasks in the realm of software development." [Pree, 1994]

  • "Design patterns focus more on reuse of recurring architectural design themes, while frameworks focus on detailed design... and implementation." [Coplien and Schmidt, 1995]

  • "A pattern addresses a recurring design problem that arises in specific design situations and presents a solution to it." [Buschmann and Meunier, et al., 1996]

  • "Patterns identify and specify abstractions that are above the level of single classes and instances, or of components." [Gamma, Helm, Johnson, and Vlissides, 1993]

But while it is helpful to draw analogies to architecture, cabinetmaking, and logic, design patterns are not just about the design of objects; they are also about interaction between objects. One possible view of some of these patterns is to consider them as communication patterns.

Some other patterns deal not just with object communication, but also with strategies for object inheritance and containment. It is the design of simple, but elegant methods of interaction that makes many design patterns so important.

Design patterns can exist at many levels, from very low-level specific solutions to broadly generalized system issues. There are now hundreds of patterns in the literature. They have been discussed in articles and at conferences at all levels of granularity. Some are examples that apply widely. A few writers have ascribed pattern behavior to class groupings that apply to just a single problem [Kurata, 1998].

Thus you don't just write a design pattern off the top of your head. Rather, most such patterns are discovered. The process of looking for these patterns is called pattern mining and is worthy of a book of its own.

The 23 design patterns included in Design Patterns all had several known applications and were on a middle level of generality, where they could easily cross application areas and encompass several objects. The authors divided these patterns into three types:

  • Creational patterns: . create objects for you, rather than your having to instantiate objects directly. Your program gains more flexibility in deciding which objects need to be created for a given case.

  • Structural patterns: . help you compose groups of objects into larger structures, such as complex user interfaces and accounting data.

  • Behavioral patterns: . help you to define the communication between objects in your system and how the flow is controlled in a complex program.

We'll be looking at Java versions of these patterns in the chapters that follow. This book takes a somewhat different approach than Design Patterns and the Smalltalk Companion; we provide at least one complete, visual Java program for each of the 23 patterns. This way you can not only examine the code snippets we provide, but run, edit, and modify the complete working programs on the accompanying CD-ROM. You'll find a list of all the programs on the CD-ROM at the end of each pattern description.

The Learning Process

We have found that learning design patterns is a multiple step process:

  1. Acceptance

  2. Recognition

  3. Internalization

First, you accept the premise that design patterns are important in your work. Then, you recognize that you need to read about design patterns in order to know when you might use them. Finally, you internalize the patterns in sufficient detail that you know which ones might help you solve a given design problem.

For some lucky people, design patterns are obvious tools, and they grasp their essential utility just by reading summaries of the patterns. For many of the rest of us, there is a slow induction period after we've read about a pattern followed by the proverbial "Aha!" when we see how we can apply them in our work. This book helps to take you to that final stage of internalization by providing complete, working programs that you can try out for yourself.

The examples in Design Patterns are brief and are in C++ or, in some cases, Smalltalk. If you are working in another language, it is helpful to have the pattern examples in your language of choice. This book attempts to fill that need for Java programmers.

A set of Java examples takes on a form that is a little different than in C++, because Java is more strict in its application of OO precepts—you can't have global variables, data structures or pointers. In addition, we'll see that Java interfaces and abstract classes are a major contributor to how we implement design patterns in Java.

Studying Design Patterns

There are several alternate ways to become familiar with these patterns. In each approach, you should read this book and the parent Design Patterns book in one order or the other. We also strongly urge you to read the Smalltalk Companion for completeness, since it provides an alternate description of each pattern. Finally, there are a number of Web sites on learning and discussing design patterns.

Notes on Object-Oriented Approaches

The fundamental reason for using design patterns is to keep classes separated and prevent them from having to know too much about one another. Equally important, these patterns help you to avoid reinventing the wheel and allow you to describe your programming approach succinctly in terms that other programmers can easily understand.

Recently, we obtained from a colleague some code that had been written by a very capable summer student. However, in order to use it in our project, we had to reorganize the objects to use the Java Foundation Classes (JFCs). We offered the revised code back to our colleague and were able to summarize our changes simply by noting that we had converted the toolbuttons to Command patterns and had implemented a Mediator pattern to process their actions. This is exactly the sort of concise communication that using design patterns promotes.

OO programmers use a number of strategies to achieve the separation of classes, among them encapsulation and inheritance. Nearly all languages that have OO capabilities support inheritance. A class that inherits from a parent class has access to all of the methods of that parent class. It also has access to all of its nonprivate variables. However, by starting your inheritance hierarchy with a complete, working class, you might be unduly restricting yourself, as well as carrying along specific method implementation baggage. Instead, Design Patterns suggest that you always

Program to an interface and not to an implementation.

Putting this more succinctly, you should define the top of any class hierarchy with an abstract class or an interface, which implements no methods but simply defines the methods that the class will support. Then, in all of your derived classes you will have more freedom to implement these methods to best suit your purposes.

The other major concept that you should recognize is object composition. This is simply the construction of objects that contain other objects, that is, encapsulation of several objects inside another one. While many beginning OO programmers use inheritance to solve every problem, as you begin to write more elaborate programs, the merits of object composition become apparent. Your new object can have the interface that is best for what you want to accomplish without having all of the methods of the parent classes. Thus the second major precept suggested by Design Patterns is

Favor object composition over inheritance.

At first this seems contrary to the customs of OO programming, but you will see any number of cases among the design patterns where we find that inclusion of one or more objects inside another is the preferred method.

The Java Foundation Classes

The Java Foundation Classes, which were introduced after Java 1.1 and incorporated into Java 1.2, are a critical part of writing good graphical Java programs. They were also known during their development as the Swing classes and still are informally referred to that way. They provide easy ways to write very professional-looking user interfaces and allow you to vary the look and feel of your interface to match the platform on which your program is running. Further, they, too, utilize a number of the basic design patterns and thus make extremely good examples for study.

Nearly all the example programs in this book use the JFC to produce the interfaces you see in the example code. Since not everyone may be familiar with these classes and since we are going to build some basic classes from the JFC to use throughout our examples, we include an appendix introducing the JFC and showing the patterns that it implements. While not a complete tutorial in every aspect of the JFC, it does present the most useful interface controls and shows how to use them.

Java Design Patterns

Each of the 23 patterns in Design Patterns is discussed in the following chapters, and each discussion includes at least one working program example that has some sort of visual interface to make it more immediate to you. Each also uses the JFC to improve the elegance of its appearance and make it a little more concrete and believable. This occurs despite the fact that the programs are necessarily simple so that the coding doesn't obscure the fundamental elegance of the pattern we are describing. However, even though Java is our target language, this isn't a book on the Java language. We make no attempt to cover all of the powerful ideas in Java; only those which we can use to exemplify patterns. For that reason, we say little or nothing about either exceptions or threads, two of Java's most important features.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset