©2010 Pearson Education, Inc., Upper Saddle River, NJ. All rights reserved. This material
is protected under all copyright laws as they currently exist. No portion of this material may
be reproduced in any form or by any means, without permission in writing from the publisher.
For the exclusive use of adopters of the book, Java (TM) How to Program, 8th Edition, by
Deitel and Deitel. ISBN 0-13-605306-8.
Q.1 Introduction
Most of the examples provided in this book are relatively small. These examples do not
require an extensive design process, because they use only a few classes and illustrate introductory programming concepts. However, some programs are more complex—they can
require thousands of lines of code or even more, contain many interactions among objects
and involve many user interactions. Larger systems, such as air-traffic control systems or
the systems that control a major bank’s thousands of automated teller machines, could contain millions of lines of code. Effective design is crucial to the proper construction of such
complex systems.
Over the past decade, the software-engineering industry has made significant progress
in the field of design patterns—proven architectures for constructing flexible and maintainable object-oriented software. Using design patterns can substantially reduce the complexity of the design process. Designing an air-traffic control system will be a somewhat
less formidable task if developers use design patterns. Design patterns benefit system developers by
•
helping to construct reliable software using proven architectures and accumulated industry expertise.
•
promoting design reuse in future systems.
•
helping identify common mistakes and pitfalls that occur when building systems.
•
helping to design systems independently of the language in which they’ll ultimately be implemented.
•
establishing a common design vocabulary among developers.
•
shortening the design phase in a software-development process.
The notion of using design patterns to construct software systems originated in the
field of architecture. Architects use a set of established architectural design elements, such
as arches and columns, when designing buildings. Designing with arches and columns is
Q.2 Creational, Structural and Behavioral Design Patterns
LXXV
a proven strategy for constructing sound buildings—these elements may be viewed as
architectural design patterns.
In software, design patterns are neither classes nor objects. Rather, designers use
design patterns to construct sets of classes and objects. To use design patterns effectively,
designers must familiarize themselves with the most popular and effective patterns used in
the software-engineering industry. In this appendix, we discuss fundamental object-oriented design patterns and architectures, as well as their importance in constructing wellengineered software.
This appendix presents several design patterns in Java, but these can be implemented in
any object-oriented language, such as C++ or Visual Basic. We describe several design patterns used by Sun Microsystems in the Java API. We use design patterns in many programs
in this book, which we’ll identify throughout our discussion. These programs provide examples of the use of design patterns to construct reliable, robust object-oriented software.
History of Object-Oriented Design Patterns
During 1991–1994, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides—
collectively known as the “Gang of Four”—used their combined expertise to write the
book Design Patterns: Elements of Reusable Object-Oriented Software. This book describes
23 design patterns, each providing a solution to a common software design problem in industry. The book groups design patterns into three categories—creational design patterns, structural design patterns and behavioral design patterns. Creational design
patterns describe techniques to instantiate objects (or groups of objects). Structural design
patterns allow designers to organize classes and objects into larger structures. Behavioral
design patterns assign responsibilities to classes and objects.
The Gang-of-Four book showed that design patterns evolved naturally through years
of industry experience. In his article Seven Habits of Successful Pattern Writers,1 John Vlissides states that “the single most important activity in pattern writing is reflection.” This
statement implies that, to create patterns, developers must reflect on, and document, their
successes (and mistakes). Developers use design patterns to capture and employ this collective industry experience, which ultimately helps them avoid repeating the same mistakes. New design patterns are being created all the time and are introduced rapidly to
designers worldwide via the Internet.
Design patterns are a somewhat advanced topic that might not appear in most introductory course sequences. As you proceed in your Java studies, design patterns will surely
increase in value. If you are a student and your instructor does not plan to include this
material in your course, we encourage you to read this material on your own.
Q.2 Creational, Structural and Behavioral Design Patterns
In Section Q.1, we mentioned that the “Gang of Four” described 23 design patterns using
three categories—creational, structural and behavioral. In this and the remaining sections
of this appendix, we discuss design patterns in each category and their importance, and how
each pattern relates to the Java material in the book. For example, several Java Swing com-
1.
Vlissides, J. Pattern Hatching: Design Patterns Applied. Reading, MA: Addison-Wesley, 1998.
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
LXXVI
Appendix Q
Design Patterns
ponents that we introduce in Chapter 14 and Chapter 25 use the Composite design pattern. Figure Q.1 identifies the 18 Gang of Four design patterns discussed in this appendix.
Section
Creational design
patterns
Structural design
patterns
Behavioral design
patterns
Section Q.2
Section Q.3
Singleton
Factory Method
Proxy
Adapter, Bridge,
Composite
Memento, State
Chain of Responsibility,
Command, Observer,
Strategy,
Template Method
Section Q.5
Section Q.6
Abstract Factory
Prototype
Decorator, Facade
Iterator
Fig. Q.1 | 18 Gang-of-Four design patterns discussed in this appendix.
Many popular patterns have been documented since the Gang-of-Four book—these
include the concurrency design patterns, which are especially helpful in the design of multithreaded systems. Section Q.4 discusses some of these patterns used in industry. Architectural patterns, as we discuss in Section Q.5, specify how subsystems interact with each
other. Figure Q.2 lists the concurrency patterns and architectural patterns that we discuss
in this appendix.
Section
Concurrency design patterns
Section Q.4
Single-Threaded Execution,
Guarded Suspension,
Balking, Read/Write Lock,
Two-Phase Termination
Section Q.5
Architectural patterns
Model-View-Controller, Layers
Fig. Q.2 | Concurrency design patterns and architectural patterns discussed in this appendix.
Q.2.1 Creational Design Patterns
Creational design patterns address issues related to the creation of objects, such as preventing a system from creating more than one object of a class (the Singleton creational
design pattern) or deferring until execution time the decision as to what types of objects
are going to be created (the purpose of the other creational design patterns discussed here).
For example, suppose we are designing a 3-D drawing program, in which the user can create several 3-D geometric objects, such as cylinders, spheres, cubes, tetrahedrons, etc. Further suppose that each shape in the drawing program is represented by an object. At
compile time, the program does not know what shapes the user will choose to draw. Based
on user input, this program should be able to determine the class from which to instantiate
an appropriate object for the shape the user selected. If the user creates a cylinder in the
GUI, our program should “know” to instantiate an object of class Cylinder. When the
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.2 Creational, Structural and Behavioral Design Patterns
LXXVII
user decides what geometric object to draw, the program should determine the specific
subclass from which to instantiate that object.
The Gang-of-Four book describes five creational patterns (four of which we discuss
in this appendix):
•
Abstract Factory (Section Q.5)
•
Builder (not discussed)
•
Factory Method (Section Q.3)
•
Prototype (Section Q.6)
•
Singleton (Section Q.2)
Singleton
Occasionally, a system should contain exactly one object of a class—that is, once the program instantiates that object, the program should not be allowed to create additional objects of that class. For example, some systems connect to a database using only one object
that manages database connections, which ensures that other objects cannot initialize unnecessary connections that would slow the system. The Singleton design pattern guarantees that a system instantiates a maximum of one object of a class.
Figure Q.3 demonstrates Java code using the Singleton design pattern. Line 4 declares
class Singleton as final, so subclasses cannot be created that could provide multiple
instantiations. Lines 10–13 declare a private constructor—only class Singleton can
instantiate a Singleton object using this constructor. Line 7 declares a static reference to
a Singleton object and invokes the private constructor. This creates the one instance of
class Singleton that will be provided to clients. When invoked, static method getSingletonInstance (lines 16–19) simply returns a copy of this reference.
Lines 9–10 of class SingletonTest (Fig. Q.4) declare two references to Singleton
objects—firstSingleton and secondSingleton. Lines 13–14 call method getSingle1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Singleton.java
// Demonstrates Singleton design pattern
public final class Singleton
{
// Singleton object to be returned by getSingletonInstance
private static final Singleton singleton = new Singleton();
// private constructor prevents instantiation by clients
private Singleton()
{
System.err.println( "Singleton object created." );
} // end Singleton constructor
// return static Singleton object
public static Singleton getInstance()
{
return singleton;
} // end method getInstance
} // end class Singleton
Fig. Q.3 | Class Singleton ensures that only one object of its class is created.
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Appendix Q
LXXVIII
Design Patterns
and assign Singleton references to firstSingleton and secondSingleton,
respectively. Line 17 tests whether these references both refer to the same Singleton
object. Figure Q.4 shows that firstSingleton and secondSingleton indeed are both references to the same Singleton object, because each time method getSingletonInstance
is called, it returns a reference to the same Singleton object.
tonInstance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// SingletonTest.java
// Attempt to create two Singleton objects
public class SingletonTest
{
// run SingletonExample
public static void main( String[] args )
{
Singleton firstSingleton;
Singleton secondSingleton;
// create Singleton objects
firstSingleton = Singleton.getInstance();
secondSingleton = Singleton.getInstance();
// the "two" Singletons should refer to same Singleton
if ( firstSingleton == secondSingleton )
System.err.println( "firstSingleton and secondSingleton " +
"refer to the same Singleton object" );
} // end main
} // end class SingletonTest
Singleton object created.
firstSingleton and secondSingleton refer to the same Singleton object
Fig. Q.4 | Class SingletonTest creates a Singleton object more than once.
Q.2.2 Structural Design Patterns
Structural design patterns describe common ways to organize classes and objects in a system. The Gang-of-Four book describes seven structural design patterns (six of which we
discuss in this appendix):
•
Adapter (Section Q.3)
•
Bridge (Section Q.3)
•
Composite (Section Q.3)
•
Decorator (Section Q.5)
•
Facade (Section Q.5)
•
Flyweight (not discussed)
•
Proxy (Section Q.2)
Proxy
An applet should always display something while images load to provide positive feedback
to users, so they know the applet is working. Whether that “something” is a smaller image
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.2 Creational, Structural and Behavioral Design Patterns
LXXIX
or a string of text informing the user that the images are loading, the Proxy design pattern
can be applied to achieve this effect. Consider loading several large images (several megabytes) in a Java applet. Ideally, we would like to see these images instantaneously—however, loading large images into memory can take time to complete (especially across a
network). The Proxy design pattern allows the system to use one object—called a proxy
object—in place of another. In our example, the proxy object could be a gauge that shows
the user what percentage of a large image has been loaded. When this image finishes loading, the proxy object is no longer needed—the applet can then display an image instead of
the proxy. Class javax.swing.JProgressBar can be used to create such proxy objects.
Q.2.3 Behavioral Design Patterns
Behavioral design patterns provide proven strategies to model how objects collaborate
with one another in a system and offer special behaviors appropriate for a wide variety of
applications. Let’s consider the Observer behavioral design pattern—a classic example illustrating collaborations between objects. For example, GUI components collaborate with
their listeners to respond to user interactions. GUI components use this pattern to process
user interface events. A listener observes state changes in a particular GUI component by
registering to handle its events. When the user interacts with that GUI component, the
component notifies its listeners (also known as its observers) that its state has changed
(e.g., a button has been pressed).
We also consider the Memento behavioral design pattern—an example of offering
special behavior for many applications. The Memento pattern enables a system to save an
object’s state, so that state can be restored at a later time. For example, many applications
provide an “undo” capability that allows users to revert to previous versions of their work.
The Gang-of-Four book describes 11 behavioral design patterns (eight of which we
discuss in this appendix):
• Chain of Responsibility (Section Q.3)
• Command (Section Q.3)
• Interpreter (not discussed)
• Iterator (Section Q.6)
• Mediator (not discussed)
• Memento (Section Q.2)
• Observer (Section Q.3)
• State (Section Q.2)
• Strategy (Section Q.3)
• Template Method (Section Q.3)
• Visitor (not discussed)
Memento
Consider a painting program, which allows a user to create graphics. Occasionally the user
may position a graphic improperly in the drawing area. Painting programs offer an “undo”
feature that allows the user to unwind such an error. Specifically, the program restores the
drawing area to its state before the user placed the graphic. More sophisticated painting
programs offer a history, which stores several states in a list, allowing the user to restore
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
LXXX
Appendix Q
Design Patterns
the program to any state in the history.The Memento design pattern allows an object to
save its state, so that—if necessary—the object can be restored to its former state.
The Memento design pattern requires three types of objects. The originator object
occupies some state—the set of attribute values at a specific time in program execution. In
our painting-program example, the drawing area acts as the originator, because it contains
attribute information describing its state—when the program first executes, the area contains no elements. The memento object stores a copy of necessary attributes associated
with the originator’s state (i.e., the memento saves the drawing area’s state). The memento
is stored as the first item in the history list, which acts as the caretaker object—the object
that contains references to all memento objects associated with the originator. Now, suppose that the user draws a circle in the drawing area. The area contains different information describing its state—a circle object centered at specified x-y coordinates. The drawing
area then uses another memento to store this information. This memento becomes the
second item in the history list. The history list displays all mementos on screen, so the user
can select which state to restore. Suppose that the user wishes to remove the circle—if the
user selects the first memento, the drawing area uses it to restore the blank drawing area.
State
In certain designs, we must convey an object’s state information or represent the various
states that an object can occupy. The State design pattern uses an abstract superclass—
called the State class—which contains methods that describe behaviors for states that an
object (called the context object) can occupy. A State subclass, which extends the State
class, represents an individual state that the context can occupy. Each State subclass contains methods that implement the State class’s abstract methods. The context contains exactly one reference to an object of the State class—this object is called the state object.
When the context changes state, the state object references the State subclass object associated with that new state.
Q.2.4 Conclusion
In this section, we listed the three types of design patterns introduced in the Gang-of-Four
book, we identified 18 of these design patterns that we discuss in this appendix and we
discussed specific design patterns: Singleton, Proxy, Memento and State. In the next section, we introduce some design patterns associated with AWT and Swing GUI components.
Q.3 Design Patterns in Packages java.awt and
javax.swing
This section introduces those design patterns associated with Java GUI components. It
will help you understand better how these components take advantage of design patterns
and how developers integrate design patterns with Java GUI applications.
Q.3.1 Creational Design Patterns
Now, we continue our treatment of creational design patterns, which provide ways to instantiate objects in a system.
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.3 Design Patterns in Packages java.awt and javax.swing
LXXXI
Factory Method
Suppose that we are designing a system that opens an image from a specified file. Several
different image formats exist, such as GIF and JPEG. We can use method createImage of
class java.awt.Component to create an Image object. For example, to create a JPEG and
GIF image in an object of a Component subclass—such as a JPanel object—we pass the
name of the image file to method createImage, which returns an Image object that stores
the image data. We can create two Image objects, each containing data for two images having entirely different structures. For example, a JPEG image can hold up to 16.7 million
colors, a GIF image up to only 256. Also, a GIF image can contain transparent pixels that
are not rendered on screen, whereas a JPEG image cannot.
Class Image is an abstract class that represents an image we can display on screen.
Using the parameter passed by the programmer, method createImage determines the specific Image subclass from which to instantiate the Image object. We can design systems to
allow the user to specify which image to create, and method createImage will determine
the subclass from which to instantiate the Image. If the parameter passed to method createImage references a JPEG file, method createImage instantiates and returns an object
of an Image subclass suitable for JPEG images. If the parameter references a GIF file, createImage instantiates and returns an object of an Image subclass suitable for GIF images.
Method createImage is an example of the Factory Method design pattern. The sole
purpose of this factory method is to create objects by allowing the system to determine
which class to instantiate at runtime. We can design a system that allows a user to specify
what type of image to create at runtime. Class Component might not be able to determine
which Image subclass to instantiate until the user specifies the image to load. For more
information on method createImage, visit
java.sun.com/javase/6/docs/api/java/awt/Component.html
Q.3.2 Structural Design Patterns
We now discuss three more structural design patterns. The Adapter design pattern helps
objects with incompatible interfaces collaborate with one another. The Bridge design pattern helps designers enhance platform independence in their systems. The Composite design pattern provides a way for designers to organize and manipulate objects.
Adapter
The Adapter design pattern provides an object with a new interface that adapts to another
object’s interface, allowing both objects to collaborate with one another. We might liken
the adapter in this pattern to an adapter for a plug on an electrical device—electrical sockets in Europe are shaped differently from those in the United States, so an adapter is needed to plug an American device into a European socket and vice versa.
Java provides several classes that use the Adapter design pattern. Objects of the concrete subclasses of these classes act as adapters between objects that generate certain events
and objects that handle the events. For example, a MouseAdapter, which we explained in
Section 14.15, adapts an object that generates MouseEvents to an object that handles
MouseEvents.
Bridge
Suppose that we are designing class Button for both the Windows and Macintosh operating systems. Class Button contains specific button information such as an Action© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
LXXXII
Appendix Q
Design Patterns
and a label. We design classes Win32Button and MacButton to extend class
Class Win32Button contains look-and-feel information on how to display a Button on the Windows operating system, and class MacButton contains “look-and-feel” information on how to display a Button on the Macintosh operating system.
Two problems arise here. First, if we create new Button subclasses, we must create corresponding Win32Button and MacButton subclasses. For example, if we create class ImageButton (a Button with an overlapping Image) that extends class Button, we must create
additional subclasses Win32ImageButton and MacImageButton. In fact, we must create
Button subclasses for every operating system we wish to support, which increases development time. Second, when a new operating system enters the market, we must create additional Button subclasses specific to it.
The Bridge design pattern avoids these problems by dividing an abstraction (e.g., a
Button) and its implementations (e.g., Win32Button, MacButton, etc.) into separate class
hierarchies. For example, the Java AWT classes use the Bridge design pattern to enable
designers to create AWT Button subclasses without needing to create additional operating-system specific subclasses. Each AWT Button maintains a reference to a ButtonPeer, which is the superclass for platform-specific implementations, such as
Win32ButtonPeer, MacButtonPeer, etc. When a programmer creates a Button object, class
Button calls factory method createButton of class Toolkit to create the platform-specific
ButtonPeer object. The Button object stores a reference to its ButtonPeer—this reference
is the “bridge” in the Bridge design pattern. When the programmer invokes methods on
the Button object, the Button object delegates the work to the appropriate lower-level
method on its ButtonPeer to fulfill the request. A designer who creates a Button subclass
called, e.g., ImageButton, does not need to create a corresponding Win32ImageButton or
MacImageButton with platform-specific image-drawing capabilities. An ImageButton is a
Button. Therefore, when an ImageButton needs to display its image, the ImageButton uses
its ButtonPeer’s Graphics object to render the image on each platform. This design pattern enables designers to create new cross-platform GUI components using a “bridge” to
hide platform-specific details.
Listener
Button.
Portability Tip Q.1
Designers often use the Bridge design pattern to enhance the platform independence of
their systems. This design pattern enables designers to create new cross-platform components using a “bridge” to hide platform-specific details.
Q.1
Composite
Designers often organize components into hierarchical structures (e.g., a hierarchy of directories and files in a file system)—each node in the structure represents a component
(e.g., a file or directory). Each node can contain references to one or more other nodes,
and if it does so, it’s called a branch (e.g., a directory containing files); otherwise, it’s called
a leaf (e.g., a file). Occasionally, a structure contains objects from several different classes
(e.g., a directory can contain files and directories). An object—called a client—that wants
to traverse the structure must determine the particular class for each node. Making this determination can be time consuming, and the structure can become hard to maintain.
In the Composite design pattern, each component in a hierarchical structure implements the same interface or extends a common superclass. This polymorphism (introduced in Chapter 10) ensures that clients can traverse all elements—branch or leaf—
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.3 Design Patterns in Packages java.awt and javax.swing
LXXXIII
uniformly in the structure and do not have to determine each component type, because all
components implement the same interface or extend the same superclass.
Java GUI components use the Composite design pattern. Consider the Swing component class JPanel, which extends class JComponent. Class JComponent extends class
java.awt.Container, which extends class java.awt.Component (Fig. Q.5). Class Container provides method add, which appends a Component object (or Component subclass
object) to that Container object. Therefore, a JPanel object may be added to any object
of a Component subclass, and any object from a Component subclass may be added to that
JPanel object. A JPanel object can contain any GUI component while remaining
unaware of its specific type. Nearly all GUI classes are both containers and components,
enabling arbitrarily complex nesting and structuring of GUIs.
java.awt.Component
java.awt.Container
javax.swing.JComponent
javax.swing.JPanel
Fig. Q.5 | Inheritance hierarchy for class JPanel.
A client, such as a JPanel object, can traverse all components uniformly in the hierarchy. For example, if the JPanel object calls method repaint of superclass Container,
method repaint displays the JPanel object and all components added to the JPanel
object. Method repaint does not have to determine each component’s type, because all
components inherit from superclass Container, which contains method repaint.
Q.3.3 Behavioral Design Patterns
This section continues our discussion on behavioral design patterns. We discuss the Chain
of Responsibility, Command, Observer, Strategy and Template Method design patterns.
Chain of Responsibility
In object-oriented systems, objects interact by sending messages to one another. Often, a
system needs to determine at runtime the object that will handle a particular message. For
example, consider the design of a three-line office phone system. When a person calls the
office, the first line handles the call—if the first line is busy, the second line handles the
call, and if the second line is busy, the third line handles the call. If all lines in the system
are busy, an automated speaker instructs the caller to wait for the next available line. When
a line becomes available, that line handles the call.
The Chain of Responsibility design pattern enables a system to determine at run
time the object that will handle a message. This pattern allows an object to send a message
to several objects in a chain. Each object in the chain either may handle the message or
pass it to the next object. For instance, the first line in the phone system is the first object
in the chain of responsibility, the second line is the second object, the third line is the third
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
LXXXIV
Appendix Q Design Patterns
object and the automated speaker is the fourth object. The final object in the chain is the
next available line that handles the message. The chain is created dynamically in response
to the presence or absence of specific message handlers.
Several Java AWT GUI components use the Chain of Responsibility design pattern
to handle certain events. For example, class java.awt.Button overrides method processEvent of class java.awt.Component to process AWTEvent objects. Method processEvent
attempts to handle the AWTEvent upon receiving it as an argument. If method processEvent determines that the AWTEvent is an ActionEvent (i.e., the Button has been pressed),
it handles the event by invoking method processActionEvent, which informs any
ActionListener registered with the Button that the Button has been pressed. If method
processEvent determines that the AWTEvent is not an ActionEvent, the method is unable
to handle it and passes it to method processEvent of superclass Component (the next listener in the chain).
Command
Applications often provide users with several ways to perform a given task. For example,
in a word processor there might be an Edit menu with menu items for cutting, copying
and pasting text. A toolbar or a popup menu could also offer the same items. The functionality the application provides is the same in each case—the different interface components for invoking the functionality are provided for the user’s convenience. However, the
same GUI component instance (e.g., JButton) cannot be used for menus, toolbars and
popup menus, so the developer must code the same functionality three times. If there were
many such interface items, repeating this functionality would become tedious and error
prone.
The Command design pattern solves this problem by enabling developers to encapsulate the desired functionality (e.g., copying text) once in a reusable object; that functionality can then be added to a menu, toolbar, popup menu or other mechanism. This design
pattern is called Command because it defines a command, or instruction, to be executed.
It allows a designer to encapsulate a command, so that it may be used among several
objects.
Observer
Suppose that we want to design a program for viewing bank account information. This
system includes class BankStatementData to store data pertaining to bank statements and
classes TextDisplay, BarGraphDisplay and PieChartDisplay to display the data. [Note:
This approach is the basis for the Model-View-Controller architecture pattern, discussed
in Section Q.5.3.] Figure Q.6 shows the design for our system. The data is displayed by
class TextDisplay in text format, by class BarGraphDisplay in bar-graph format and by
class PieChartDisplay as a pie chart. We want to design the system so that the BankStatementData object notifies the objects displaying the data of a change in the data. We
also want to design the system to loosen coupling—the degree to which classes depend on
each other in a system.
Software Engineering Observation Q.1
Loosely coupled classes are easier to reuse and modify than are tightly coupled classes, which
depend heavily on each other. A modification in a class in a tightly coupled system usually
results in modifying other classes in that system. A modification to one of a group of loosely
coupled classes would require little or no modification to the other classes.
Q.1
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.3 Design Patterns in Packages java.awt and javax.swing
LXXXV
The Observer design pattern is appropriate for systems like that of Fig. Q.6. This
pattern promotes loose coupling between a subject object and observer objects—a subject
notifies the observers when the subject changes state. When notified by the subject, the
observers change in response. In our example, the BankStatementData object is the subject, and the objects displaying the data are the observers. A subject can notify several
observers; therefore, the subject has a one-to-many relationship with the observers.
Observers
TextDisplay
Subject
BankStatementData
ifies
not
notifies
BarGraphDisplay
not
ifies
PieChartDisplay
Fig. Q.6 | Basis for the Observer design pattern.
The Java API contains classes that use the Observer design pattern. Class
represents a subject. Class Observable provides method addObserver, which takes a java.util.Observer argument. Interface Observer allows the
Observable object to notify the Observer when the Observable object changes state. The
Observer can be an instance of any class that implements interface Observer; because the
Observable object invokes methods declared in interface Observer, the objects remain
loosely coupled. If a developer changes the way in which a particular Observer responds
to changes in the Observable object, the developer does not need to change the object.
The Observable object interacts with its Observers only through interface Observer,
which enables the loose coupling.
The Swing GUI components use the Observer design pattern. GUI components collaborate with their listeners to respond to user interactions. For example, an ActionListener
observes state changes in a JButton (the subject) by registering to handle that JButton’s
events. When pressed by the user, the JButton notifies its ActionListener objects (the
observers) that the JButton’s state has changed (i.e., the JButton has been pressed).
java.util.Observable
Strategy
The Strategy design pattern is similar to the State design pattern (discussed in
Section Q.2.3). We mentioned that the State design pattern contains a state object, which
encapsulates the state of a context object. The Strategy design pattern contains a strategy
object, which is analogous to the State design pattern’s state object. The key difference is
that the strategy object encapsulates an algorithm rather than state information.
For example, java.awt.Container components implement the Strategy design pattern using LayoutManagers (discussed in Section 14.18) as strategy objects. In package
java.awt, classes FlowLayout, BorderLayout and GridLayout implement interface LayoutManager. Each class uses method addLayoutComponent to add GUI components to a
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
LXXXVI
Appendix Q Design Patterns
Container object. However, each method uses a different algorithm to display these GUI
components: A FlowLayout displays them in a left-to-right sequence, a BorderLayout displays them in five regions and a GridLayout displays them in row-column format.
Class Container contains a reference to a LayoutManager object (the strategy object).
An interface reference (i.e., the reference to the LayoutManager object) can hold references
to objects of classes that implement that interface (i.e., the FlowLayout, BorderLayout or
GridLayout objects), so the LayoutManager object can reference a FlowLayout, BorderLayout or GridLayout at any time. Class Container can change this reference through
method setLayout to select different layouts at runtime.
Class FlowLayoutFrame (Fig. 14.39) demonstrates the application of the Strategy pattern—line 23 declares a new FlowLayout object and line 25 invokes the Container
object’s method setLayout to assign the FlowLayout object to the Container object. In
this example, the FlowLayout provides the strategy for laying out the components.
Template Method
The Template Method design pattern also deals with algorithms. The Strategy design pattern allows several objects to contain distinct algorithms. However, the Template Method
design pattern requires all objects to share a single algorithm defined by a superclass.
For example, consider the design of Fig. Q.6, which we presented in the Observer
design pattern discussion earlier in this section. Objects of classes TextDisplay, BarGraphDisplay and PieChartDisplay use the same basic algorithm for acquiring and displaying the data—get all statements from the BankStatementData object, parse the
statements, then display the statements. The Template Method design pattern allows us
to create an abstract superclass called BankStatementDisplay that provides the common
algorithm for displaying the data. In this example, the algorithm invokes abstract methods
getData, parseData and displayData. Classes TextDisplay, BarGraphDisplay and
PieChartDisplay extend class BankStatementDisplay to inherit the algorithm, so each
object can use the same algorithm. Each BankStatementDisplay subclass then overrides
each method in a way specific to that subclass, because each class implements the algorithm differently. For example, classes TextDisplay, BarGraphDisplay and PieChartDisplay might get and parse the data identically, but each displays that data differently.
The Template Method design pattern allows us to extend the algorithm to other
BankStatementDisplay subclasses—e.g., we could create classes, such as LineGraphDisplay or class 3DimensionalDisplay, that use the same algorithm inherited from class
BankStatementDisplay and provide different implementations of the abstract methods
the algorithm calls.
Q.3.4 Conclusion
In this section, we discussed how Swing components take advantage of design patterns and
how developers can integrate design patterns with GUI applications in Java. In the next
section, we discuss concurrency design patterns, which are particularly useful for developing multithreaded systems.
Q.4 Concurrency Design Patterns
Many additional design patterns have been discovered since the publication of the Gang
of Four book, which introduced patterns involving object-oriented systems. Some of these
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.4 Concurrency Design Patterns
LXXXVII
new patterns involve specific types of object-oriented systems, such as concurrent, distributed or parallel systems. In this section, we discuss concurrency patterns to complement
our discussion of multithreaded programming in Chapter 26.
Concurrency Design Patterns
Multithreaded programming languages such as Java allow designers to specify concurrent
activities—that is, those that operate in parallel with one another. Designing concurrent
systems improperly can introduce concurrency problems. For example, two objects attempting to alter shared data at the same time could corrupt that data. In addition, if two
objects wait for one another to finish tasks, and if neither can complete their task, these
objects could potentially wait forever—a situation called deadlock. Using Java, Doug Lea2
and Mark Grand3 documented concurrency patterns for multithreaded design architectures to prevent various problems associated with multithreading. We provide a partial list
of these design patterns:
• The Single-Threaded Execution design pattern (Grand, 2002) prevents several
threads from executing the same method of another object concurrently.
Chapter 26 discusses various techniques that can be used to apply this pattern.
• The Guarded Suspension design pattern (Lea, 2000) suspends a thread’s activity
and resumes that thread’s activity when some condition is satisfied.
• The Balking design pattern (Lea, 2000) ensures that a method will balk—that is,
return without performing any actions—if an object occupies a state that cannot
execute that method. A variation of this pattern is that the method throws an exception describing why that method is unable to execute—for example, a method
throwing an exception when accessing a data structure that does not exist.
• The Read/Write Lock design pattern (Lea, 2000) allows multiple threads to obtain concurrent read access on an object but prevents multiple threads from obtaining concurrent write access on that object. Only one thread at a time may
obtain write access to an object—when that thread obtains write access, the object is locked to all other threads.
• The Two-Phase Termination design pattern (Grand, 2002) uses a two-phase
termination process for a thread to ensure that a thread has the opportunity to
free resources—such as other spawned threads—in memory (phase one) before
termination (phase two). In Java, a Runnable object can use this pattern in method run. For instance, method run can contain an infinite loop that is terminated
by some state change—upon termination, method run can invoke a private
method responsible for stopping any other spawned threads (phase one). The
thread then terminates after method run terminates (phase two).
In the next section, we return to the Gang of Four design patterns. Using the material
introduced in Chapter 17 and Chapter 27, we identify those classes in package java.io
and java.net that use design patterns.
2.
3.
Lea, D. Concurrent Programming in Java, Second Edition: Design Principles and Patterns. Boston: Addison-Wesley, 2000.
Grand, M. Patterns in Java; A Catalog of Reusable Design Patterns Illustrated with UML, Second Edition, Volume I. New York: John Wiley and Sons, 2002.
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
LXXXVIII
Appendix Q Design Patterns
Q.5 Design Patterns Used in Packages java.io and
java.net
This section introduces those design patterns associated with the Java file, streams and networking packages.
Q.5.1 Creational Design Patterns
We now continue our discussion of creational design patterns.
Abstract Factory
Like the Factory Method design pattern, the Abstract Factory design pattern allows a system to determine the subclass from which to instantiate an object at runtime. Often, this
subclass is unknown during development. However, Abstract Factory uses an object
known as a factory that uses an interface to instantiate objects. A factory creates a product,
which in this case is an object of a subclass determined at runtime.
The Java socket library in package java.net uses the Abstract Factory design pattern.
A socket describes a connection, or a stream of data, between two processes. Class Socket
references an object of a SocketImpl subclass. Class Socket also contains a static reference to an object implementing interface SocketImplFactory. The Socket constructor
invokes method createSocketImpl of interface SocketImplFactory to create the SocketImpl object. The object that implements interface SocketImplFactory is the factory,
and an object of a SocketImpl subclass is the product of that factory. The system cannot
specify the SocketImpl subclass from which to instantiate until runtime, because the
system has no knowledge of what type of Socket implementation is required (e.g., a socket
configured to the local network’s security requirements). Method createSocketImpl
decides the SocketImpl subclass from which to instantiate the object at runtime.
Q.5.2 Structural Design Patterns
This section concludes our discussion of structural design patterns.
Decorator
Let’s reexamine class CreateSequentialFile (Fig. 17.17). Lines 20–21 of this class allow
a FileOutputStream object, which writes bytes to a file, to gain the functionality of an ObjectOutputStream, which provides methods for writing entire objects to an OutputStream. Class CreateSequentialFile appears to “wrap” an ObjectOutputStream object
around a FileOutputStream object. The fact that we can dynamically add the behavior of
an ObjectOutputStream to a FileOutputStream obviates the need for a separate class
called ObjectFileOutputStream, which would implement the behaviors of both classes.
Lines 20–21 of class CreateSequentialFile show an example of the Decorator
design pattern, which allows an object to gain additional functionality dynamically. Using
this pattern, designers do not have to create separate, unnecessary classes to add responsibilities to objects of a given class.
Let’s consider a more complex example to discover how the Decorator design pattern
can simplify a system’s structure. Suppose that we wanted to enhance the I/O performance
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.5 Design Patterns Used in Packages java.io and java.net
LXXXIX
of the previous example by using a BufferedOutputStream. Using the Decorator design
pattern, we would write
output = new ObjectOutputStream(
new BufferedOutputStream(
new FileOutputStream( fileName ) ) );
We can combine objects in this manner, because ObjectOutputStream, Bufferedand FileOutputStream extend abstract superclass OutputStream, and each
subclass constructor takes an OutputStream object as a parameter. If the stream objects in
package java.io did not use the Decorator pattern (i.e., did not satisfy these two requirements), package java.io would have to provide classes BufferedFileOutputStream,
ObjectBufferedOutputStream, ObjectBufferedFileOutputStream and ObjectFileOutputStream. Consider how many classes we would have to create if we combined even
more stream objects without applying the Decorator pattern.
OutputStream
Facade
When driving, you know that pressing the gas pedal accelerates your car, but you are unaware of exactly how it does so. This principle is the foundation of the Facade design pattern, which allows an object—called a facade object—to provide a simple interface for the
behaviors of a subsystem (an aggregate of objects that comprise collectively a major system
responsibility). The gas pedal, for example, is the facade object for the car’s acceleration
subsystem, the steering wheel is the facade object for the car’s steering subsystem and the
brake is the facade object for the car’s deceleration subsystem. A client object uses the facade object to access the objects behind the facade. The client remains unaware of how the
objects behind the facade fulfill responsibilities, so the subsystem complexity is hidden
from the client. When you press the gas pedal, you act as a client object. The Facade design
pattern reduces system complexity, because a client interacts with only one object (the facade) to access the behaviors of the subsystem the facade represents. This pattern shields
applications developers from subsystem complexities. Developers need to be familiar with
only the operations of the facade object, rather than with the more detailed operations of
the entire subsystem. The implementation behind the facade may be changed without
changes to the clients.
In package java.net, an object of class URL is a facade object. This object contains a
reference to an InetAddress object that specifies the host computer’s IP address. The URL
facade object also references an object from class URLStreamHandler, which opens the
URL connection. The client object that uses the URL facade object accesses the InetAddress object and the URLStreamHandler object through the facade object. However, the
client object does not know how the objects behind the URL facade object accomplish their
responsibilities.
Q.5.3 Architectural Patterns
Design patterns allow developers to design specific parts of systems, such as abstracting object instantiations or aggregating classes into larger structures. Design patterns also promote loose coupling among objects. Architectural patterns promote loose coupling
among subsystems. These patterns specify how subsystems interact with one another.4 We
introduce the popular Model-View-Controller and Layers architectural patterns.
4.
R. Hartman. “Building on Patterns.” Application Development Trends, May 2001: 19–26.
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
XC
Appendix Q Design Patterns
MVC
Consider the design of a simple text editor. In this program, the user enters text from the
keyboard and formats it using the mouse. Our program stores this text and format information into a series of data structures, then displays this information on screen for the user
to read what has been inputted.
This program adheres to the Model-View-Controller (MVC) architectural pattern,
which separates application data (contained in the model) from graphical presentation
components (the view) and input-processing logic (the controller). Figure Q.7 shows the
relationships between components in MVC.
Controller
modifies
notifies
Model
View
Fig. Q.7 | Model-View-Controller Architecture.
The controller implements logic for processing user inputs. The model contains application data, and the view presents the data stored in the model. When a user provides some
input, the controller modifies the model with the given input. With regard to the texteditor example, the model might contain only the characters that make up the document.
When the model changes, it notifies the view of the change so that it can update its presentation with the changed data. The view in a word processor might display characters
using a particular font, with a particular size, etc.
MVC does not restrict an application to a single view and a single controller. In a
more sophisticated program (such as a word processor), there might be two views of a document model. One view might display an outline of the document and the other might
display the complete document. The word processor also might implement multiple controllers—one for handling keyboard input and another for handling mouse selections. If
either controller makes a change in the model, both the outline view and the print-preview
window will show the change immediately when the model notifies all views of changes.
Another key benefit to the MVC architectural pattern is that developers can modify
each component individually without having to modify the others. For example, developers could modify the view that displays the document outline without having to modify
either the model or other views or controllers.
Layers
Consider the design in Fig. Q.8, which presents the basic structure of a three-tier application, in which each tier contains a unique system component.
The information tier (also called the bottom tier) maintains data for the application,
typically storing it in a database. The information tier for an online store may contain
product information, such as descriptions, prices and quantities in stock, and customer
information, such as user names, billing addresses and credit-card numbers.
The middle tier acts as an intermediary between the information tier and the client
tier. The middle tier processes client-tier requests, and reads data from and writes data to
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.5 Design Patterns Used in Packages java.io and java.net
XCI
Client tier
(Top tier)
Middle tier
Information tier
(Bottom tier)
Application
Database
Fig. Q.8 | Three-tier application model.
the database. It then processes data from the information tier and presents the content to
the client tier. This processing is the application’s business logic, which handles such tasks
as retrieving data from the information tier, ensuring that data is reliable before updating
the database and presenting data to the client tier. For example, the business logic associated with the middle tier for the online store can verify a customer’s credit card with the
credit-card issuer before the warehouse ships the customer’s order. This business logic
could then store (or retrieve) the credit information in the database and notify the client
tier that the verification was successful.
The client tier (also called the top tier) is the application’s user interface, such as a
standard web browser. Users interact directly with the application through the user interface. The client tier interacts with the middle tier to make requests and retrieve data from
the information tier. The client tier then displays data retrieved from the middle tier.
Figure Q.8 is an implementation of the Layers architectural pattern, which divides
functionality into separate layers. Each layer contains a set of system responsibilities and
depends on the services of only the next lower layer. In Fig. Q.8, each tier corresponds to
a layer. This architectural pattern is useful, because a designer can modify one layer
without having to modify the others. For example, a designer could modify the information tier in Fig. Q.8 to accommodate a particular database product but would not have to
modify either the client tier or the middle tier.
Q.5.4 Conclusion
In this section, we discussed how packages java.io and java.net take advantage of specific design patterns and how developers can integrate design patterns with networking/
file-processing applications in Java. We also introduced the MVC and Layers architectural
patterns, which both assign system functionality to separate subsystems. These patterns
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
XCII
Appendix Q Design Patterns
make designing a system easier for developers. In the next section, we conclude our presentation of design patterns by discussing those patterns used in package java.util.
Q.6 Design Patterns Used in Package java.util
In this section, we use the material on data structures and collections discussed in
Chapters 22–20 to identify classes from package java.util that use design patterns.
Q.6.1 Creational Design Patterns
We conclude our discussion of creational design patterns by presenting the Prototype design pattern.
Prototype
Sometimes a system must make a copy of an object but will not “know” that object’s class
until execution time. For example, consider the drawing program design of Exercise 10.1
in the optional GUI and Graphics Case Study—classes MyLine, MyOval and MyRectangle
represent “shape” classes that extend abstract superclass MyShape. We could modify this
exercise to allow the user to create, copy and paste new instances of class MyLine into the
program. The Prototype design pattern allows an object—called a prototype—to return
a copy of that prototype to a requesting object—called a client. Every prototype must belong to a class that implements a common interface that allows the prototype to clone itself. For example, the Java API provides method clone from class java.lang.Object and
interface java.lang.Cloneable—any object from a class implementing Cloneable can
use method clone to copy itself. Specifically, method clone creates a copy of an object,
then returns a reference to that object. If we designate class MyLine as the prototype for
Exercise 10.1, then class MyLine must implement interface Cloneable. To create a new
line in our drawing, we clone the MyLine prototype. To copy a preexisting line, we clone
that object. Method clone also is useful in methods that return a reference to an object,
but the developer does not want that object to be altered through that reference—method
clone returns a reference to the copy of the object instead of returning that object’s reference. For more information on interface Cloneable, visit
java.sun.com/javase/6/docs/api/java/lang/Cloneable.html
Q.6.2 Behavioral Design Patterns
We conclude our discussion of behavioral design patterns by discussing the Iterator design
pattern.
Iterator
Designers use data structures such as arrays, linked lists and hash tables to organize data in
a program. The Iterator design pattern allows objects to access individual objects from any
data structure without “knowing” the data structure’s behavior (such as traversing the
structure or removing an element from that structure) or how that data structure stores
objects. Instructions for traversing the data structure and accessing its elements are stored
in a separate object called an iterator. Each data structure can create an iterator—each iterator implements methods of a common interface to traverse the data structure and access
its data. A client can traverse two differently structured data structures—such as a linked
list and a hash table—in the same manner, because both data structures provide an iterator
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.
Q.7 Wrap-Up
XCIII
object that belongs to a class implementing a common interface. Java provides interface
from package java.util, which we used in Fig. 20.2.
Iterator
Q.7 Wrap-Up
In this appendix, we’ve introduced the importance, usefulness and prevalence of design
patterns. In their book Design Patterns, Elements of Reusable Object-Oriented Software, the
Gang of Four described 23 design patterns that provide proven strategies for building systems. Each pattern belongs to one of three pattern categories—creational patterns address
issues related to object creation; structural patterns provide ways to organize classes and
objects in a system; and behavioral patterns offer strategies for modeling how objects collaborate with one another in a system.
Of the 23 design patterns, we discussed 18 of the more popular ones used by the Java
community. The discussion was divided according to how certain packages of the Java
API—such as package java.awt, javax.swing, java.io, java.net and java.util—use
these design patterns. Also discussed were patterns not described by the Gang of Four,
such as concurrency patterns, which are useful in multithreaded systems, and architectural
patterns, which help designers assign functionality to various subsystems in a system. We
motivated each pattern—explained why it’s important and explained how it may be used.
When appropriate, we supplied several examples in the form of real-world analogies (e.g.,
the adapter in the Adapter design pattern is similar to an adapter for a plug on an electrical
device). You learned also how Java API packages take advantage of design patterns (e.g.,
Swing GUI components use the Observer design pattern to collaborate with their listeners
to respond to user interactions). We provided examples of how certain programs in this
book used design patterns.
We hope that you view this appendix as a beginning to further study of design patterns. Design patterns are used most prevalently in the J2EE (Java 2 Platform, Enterprise
Edition) community, where systems tend to be exceedingly large and complex, and where
robustness, portability and performance are so critical. However, even beginner programmers can benefit from early exposure to design patterns. We recommend that you visit our
Java Design Patterns Resource Center (www.deitel.com/JavaDesignPatterns/), and
that you read the Gang-of-Four book. This information will help you build better systems
using the collective wisdom of the object-technology industry.
© 2010 Pearson Education, Inc., Upper Saddle River, NJ. All Rights Reserved.