___________________________________________
Note: This document requires the installation of the fonts Georgia, Verdana and Andale Mono (code font) for proper viewing. These can be found at: http://sourceforge.net/project/showfiles.php?group_id=34153&release_id=105355
Modifications in Revision 0.9:
· Prose has still had little/no work. My current goal is to get the structure and examples worked out so that the seminar works well. Once it has been proven in the seminars, then I will spend time on the prose.
· Added proxy:PoolManager.java to make a more generic/customizeable Pool Manager, and modified proxy:ConnectionPoolProxyDemo.java accordingly [[ Still need to decide what to return when you run out of objects in the pool ]]
· Changed PoolManager.java to use an ArrayList (and thus does not require a fixed size at initialization)
· Added KissingPrincess.java to State description, as a motivational example for the pattern
· Added a simple Flyweight example
· Simplified the enumeration in PaperScissorsRock.java
Modifications in Revision 0.8:
· Changed Bridge example to improve clarity.
· Removed superscripts for better viewing with IE (see note above)
Modifications in Revision 0.7:
· NOTE primary changes have been made to structure of book and code examples, but not to prose. Prose can be considered to be mostly a mess in this revision.
· Complete reorganization under headings that attempt to describe the problems you are trying to solve with a pattern.
· Addition of placeholders for the remainder of the GoF patterns
· Addition of “Simplifying Idioms” section and examples
· Addition of Builder section and examples
· Removed unit-testing chapter; replaced with reference to “new” JUnit (which uses reflection)
· (4-30-2003) Added Ant build.xml files, and support files from TIJ necessary to do a full standalone build. You should be able to type “ant” from the code root directory and get a successful build.
· Dramatically simplified chainofresponsibility:FindMinima.java
· Added object pool/connection pool examples
· Refactored small things in many examples
· Some exercises may have been left behind when patterns were moved.
· For simplicity, saved from Word into a single HTML document, using “filtered” version to remove Office stuff. Seems to work pretty well; checked it with both IE and Mozilla (actually seems to work better on Mozilla than on IE!).
TODO:
· Reconfigure for new backtalk system
· Replace references to TIJ2 with TIJ3
Thinking
in
Patterns
Problem-Solving Techniques using Java
Bruce Eckel
President, MindView, Inc.
Contents
A word about checked exceptions
Proxy: fronting for another object
State: changing object behavior
Iterators: decoupling algorithms from containers
Strategy: choosing the algorithm at run-time
Package as a variation of Façade
Command: choosing the operation at run-time
Visitor, a type of multiple dispatching
Inheriting from Java library classes
Creating Java classes with Jython
Building the Java classes from the Python code
The Java-Python Extension (JPE)
Table-driven code: configuration flexibility
Table-driven code using anonymous inner classes
A pattern for prototyping creation
Parsing Trash from an external file
The material in this book has been developed in conjunction with a seminar that I have given for several years, mostly with Bill Venners. Bill and I have given many iterations of this seminar and we’ve changed it many times over the years as we both have learned more about patterns and about giving the seminar.
In the process we’ve both produced more than enough information for us each to have our own seminars, an urge that we’ve both strongly resisted because we have so much fun giving the seminar together. We’ve given the seminar in numerous places in the US, as well as in Prague (where we try to have a mini-conference every Spring together with a number of other seminars). We’ve also given it as an on-site seminar.
A great deal of appreciation goes to the people who have participated in these seminars over the years, as they have helped me work through these ideas and to refine them. I hope to be able to continue to form and develop these kinds of ideas through this book and seminar for many years to come.
This book will not stop here, either. After much pondering, I’ve realized that I want Thinking in Python to be, initially, a translation of this book rather than an introduction to Python (there are already plenty of fine introductions to that superb language). I find this prospect to be much more exciting than the idea of struggling through another language tutorial (my apologies to those who were hoping for that).
This is a book about design that I have been working on for years, basically ever since I first started trying to read Design Patterns (Gamma, Helm, Johnson & Vlissides, Addison-Wesley, 1995), commonly referred to as the Gang of Four[1] or just GoF).
There is a chapter on design patterns in the first edition of Thinking in C++, which has evolved in Volume 2 of the second edition of Thinking in C++, and you’ll also find a chapter on patterns in the first edition of Thinking in Java (I took it out of the second edition because that book was getting too big, and also because I had decided to write this book).
This is not an introductory book. I am assuming that you have worked your way through Thinking in Java or an equivalent text before coming to this book.
In addition, I assume you have more than just a grasp of the syntax of Java. You should have a good understanding of objects and what they’re about, including polymorphism. Again, these are topics covered in Thinking in Java.
On the other hand, by going through this book you’re going to learn a lot about object-oriented programming by seeing objects used in many different situations. If your knowledge of objects is rudimentary, it will get much stronger in the process of understanding the designs in this book.
In a book that has “problem-solving techniques” in its subtitle, it’s worth mentioning one of the biggest pitfalls in programming: premature optimization. Every time I bring this concept forward, virtually everyone agrees to it. Also, everyone seems to reserve in their own mind a special case “except for this thing that I happen to know is a particular problem.”
The reason I call this the Y2K syndrome has to do with that special knowledge. Computers are a mystery to most people, so when someone announced that those silly computer programmers had forgotten to put in enough digits to hold dates past the year 1999, then suddenly everyone became a computer expert – “these things aren’t so difficult after all, if I can see such an obvious problem.” For example, my background was originally in computer engineering, and I started out by programming embedded systems. As a result, I know that many embedded systems have no idea what the date or time is, and even if they do that data often isn’t used in any important calculations. And yet I was told in no uncertain terms that all the embedded systems were going to crash on January 1, 2000. As far as I can tell the only memory that was lost on that particular date was that of the people who were predicting doom – it’s as if they had never said any of that stuff.
The point is that it’s very easy to fall into a habit of thinking that the particular algorithm or piece of code that you happen to partly or thoroughly understand is naturally going to be the bottleneck in your system, simply because you can imagine what’s going on in that piece of code and so you think that it must somehow be much less efficient than all the other pieces of code that you don’t know about. But unless you’ve run actual tests, typically with a profiler, you can’t really know what’s going on. And even if you are right, that a piece of code is very inefficient, remember that most programs spend something like 90% of their time in less than 10% of the code in the program, so unless the piece of code you’re thinking about happens to fall into that 10% it isn’t going to be important.
“We should forget about small efficiencies, say about 97% of the time: Premature optimization is the root of all evil.”—Donald Knuth
One of the terms you will see used over and over in design patterns literature is context. In fact, one common definition of a design pattern is “a solution to a problem in a context.” The GoF patterns often have a “context object” that the client programmer interacts with. At one point it occurred to me that such objects seemed to dominate the landscape of many patterns, and so I began asking what they were about.
The context object often acts as a little façade to hide the complexity of the rest of the pattern, and in addition it will often be the controller that manages the operation of the pattern. Initially, it seemed to me that these were not really essential to the implementation, use and understanding of the pattern. However, I remembered one of the more dramatic statements made in the GoF: “prefer composition to inheritance.” The context object allows you to use the pattern in a composition, and that may be it’s primary value.
1) The great value of exceptions is the unification of error reporting: a standard mechanism by which to report errors, rather than the popourri of ignorable approaches that we had in C (and thus, C++, which only adds exceptions to the mix, and doesn't make it the exclusive approach). The big advantage Java has over C++ is that exceptions are the only way to report errors.
2) "Ignorable" in the previous paragraph is the other issue. The theory is that if the compiler forces the programmer to either handle the exception or pass it on in an exception specification, then the programmer's attention will always be brought back to the possibility of errors and they will thus properly take care of them. I think the problem is that this is an untested assumption we're making as language designers that falls into the field of psychology. My theory is that when someone is trying to do something and you are constantly prodding them with annoyances, they will use the quickest device available to make those annoyances go away so they can get their thing done, perhaps assuming they'll go back and take out the device later. I discovered I had done this in the first edition of Thinking in Java:
...
} catch (SomeKindOfException e) {}
And then more or less forgot it until the rewrite. How many people thought this was a good example and followed it? Martin Fowler began seeing the same kind of code, and realized people were stubbing out exceptions and then they were disappearing. The overhead of checked exceptions was having the opposite effect of what was intended, something that can happen when you experiment (and I now believe that checked exceptions were an experiment based on what someone thought was a good idea, and which I believed was a good idea until recently).
When I started using Python, all the exceptions appeared, none were accidentally "disappeared." If you *want* to catch an exception, you can, but you aren't forced to write reams of code all the time just to be passing the exceptions around. They go up to where you want to catch them, or they go all the way out if you forget (and thus they remind you) but they don't vanish, which is the worst of all possible cases. I now believe that checked exceptions encourage people to make them vanish. Plus they make much less readable code.
In the end, I think we must realize the experimental nature of exceptions and look at them carefully before assuming that everything about exceptions in Java are good. I believe that having a single mechanism for handling errors is excellent, and I believe that using a separate channel (the exception handling mechanism) for moving the exceptions around is good. But I do remember one of the early arguments for exception handling in C++ was that it would allow the programmer to separate the sections of code where you just wanted to get work done from the sections where you handled errors, and it seems to me that checked exceptions do not do this; instead, they tend to intrude (a lot) into your "normal working code" and thus are a step backwards. My experience with Python exceptions supports this, and unless I get turned around on this issue I intend to put a lot more RuntimeExceptions into my Java code.
“Design patterns help you learn from others' successes instead of your own failures[2].”
Probably the most important step forward in object-oriented design is the “design patterns” movement, chronicled in Design Patterns (ibid)[3]. That book shows 23 different solutions to particular classes of problems. In this book, the basic concepts of design patterns will be introduced along with examples. This should whet your appetite to read Design Patterns by Gamma, et. al., a source of what has now become an essential, almost mandatory, vocabulary for OOP programmers.
The latter part of this book contains an example of the design evolution process, starting with an initial solution and moving through the logic and process of evolving the solution to more appropriate designs. The program shown (a trash sorting simulation) has evolved over time, and you can look at that evolution as a prototype for the way your own design can start as an adequate solution to a particular problem and evolve into a flexible approach to a class of problems.
Initially, you can think of a pattern as an especially clever and insightful way of solving a particular class of problems. That is, it looks like a lot of people have worked out all the angles of a problem and have come up with the most general, flexible solution for it. The problem could be one you have seen and solved before, but your solution probably didn’t have the kind of completeness you’ll see embodied in a pattern.
Although they’re called “design patterns,” they really aren’t tied to the realm of design. A pattern seems to stand apart from the traditional way of thinking about analysis, design, and implementation. Instead, a pattern embodies a complete idea within a program, and thus it can sometimes appear at the analysis phase or high-level design phase. This is interesting because a pattern has a direct implementation in code and so you might not expect it to show up before low-level design or implementation (and in fact you might not realize that you need a particular pattern until you get to those phases).
The basic concept of a pattern can also be seen as the basic concept of program design: adding a layer of abstraction. Whenever you abstract something you’re isolating particular details, and one of the most compelling motivations behind this is to separate things that change from things that stay the same. Another way to put this is that once you find some part of your program that’s likely to change for one reason or another, you’ll want to keep those changes from propagating other changes throughout your code. Not only does this make the code much cheaper to maintain, but it also turns out that it is usually simpler to understand (which results in lowered costs).
Often, the most difficult part of developing an elegant and cheap-to-maintain design is in discovering what I call “the vector of change.” (Here, “vector” refers to the maximum gradient and not a container class.) This means finding the most important thing that changes in your system, or put another way, discovering where your greatest cost is. Once you discover the vector of change, you have the focal point around which to structure your design.
So the goal of design patterns is to isolate changes in your code. If you look at it this way, you’ve been seeing some design patterns already in this book. For example, inheritance can be thought of as a design pattern (albeit one implemented by the compiler). It allows you to express differences in behavior (that’s the thing that changes) in objects that all have the same interface (that’s what stays the same). Composition can also be considered a pattern, since it allows you to change—dynamically or statically—the objects that implement your class, and thus the way that class works.
You’ve also already seen another pattern that appears in Design Patterns: the iterator (Java 1.0 and 1.1 capriciously calls it the Enumeration; Java 2 containers use “iterator”). This hides the particular implementation of the container as you’re stepping through and selecting the elements one by one. The iterator allows you to write generic code that performs an operation on all of the elements in a sequence without regard to the way that sequence is built. Thus your generic code can be used with any container that can produce an iterator.
One of the events that’s occurred with the rise of design patterns is what could be thought of as the “pollution” of the term – people have begun to use the term to mean just about anything synonymous with “good.” After some pondering, I’ve come up with a sort of hierarchy describing a succession of different types of categories:
1. Idiom: how we write code in a particular language to do this particular type of thing. This could be something as common as the way that you code the process of stepping through an array in C (and not running off the end).
2. Specific Design: the solution that we came up with to solve this particular problem. This might be a clever design, but it makes no attempt to be general.
3. Standard Design: a way to solve this kind of problem. A design that has become more general, typically through reuse.
4. Design Pattern: how to solve an entire class of similar problem. This usually only appears after applying a standard design a number of times, and then seeing a common pattern throughout these applications.
I feel this helps put things in perspective, and to show where something might fit. However, it doesn’t say that one is better than another. It doesn’t make sense to try to take every problem solution and generalize it to a design pattern – it’s not a good use of your time, and you can’t force the discovery of patterns that way; they tend to be subtle and appear over time.
One could also argue for the inclusion of Analysis Pattern and Architectural Pattern in this taxonomy.
(Update from slides to here)
When I put out a call for ideas in my newsletter[4], a number of suggestions came back which turned out to be very useful, but different than the above classification, and I realized that a list of design principles is at least as important as design structures, but for a different reason: these allow you to ask questions about your proposed design, to apply tests for quality.
· Principle of least astonishment (don’t be astonishing).
· Make common things easy, and rare things possible
· Consistency. One thing has become very clear to me, especially because of Python: the more random rules you pile onto the programmer, rules that have nothing to do with solving the problem at hand, the slower the programmer can produce. And this does not appear to be a linear factor, but an exponential one.
· Law of Demeter: a.k.a. “Don’t talk to strangers.” An object should only reference itself, its attributes, and the arguments of its methods.
· Subtraction: a design is finished when you cannot take anything else away.
· Simplicity before generality[5]. (A variation of Occam’s Razor, which says “the simplest solution is the best”). A common problem we find in frameworks is that they are designed to be general purpose without reference to actual systems. This leads to a dizzying array of options that are often unused, misused or just not useful. However, most developers work on specific systems, and the quest for generality does not always serve them well. The best route to generality is through understanding well-defined specific examples. So, this principle acts as the tie breaker between otherwise equally viable design alternatives. Of course, it is entirely possible that the simpler solution is the more general one.
· Reflexivity (my suggested term). One abstraction per class, one class per abstraction. Might also be called Isomorphism.
· Independence or Orthogonality. Express independent ideas independently. This complements Separation, Encapsulation and Variation, and is part of the Low-Coupling-High-Cohesion message.
· Once and once only: Avoid duplication of logic and structure where the duplication is not accidental, ie where both pieces of code express the same intent for the same reason.
In the process of brainstorming this idea, I hope to come up with a small handful of fundamental ideas that can be held in your head while you analyze a problem. However, other ideas that come from this list may end up being useful as a checklist while walking through and analyzing your design.
The Design Patterns book discusses 23 different patterns, classified under three purposes (all of which revolve around the particular aspect that can vary). The three purposes are:
1. Creational: how an object can be created. This often involves isolating the details of object creation so your code isn’t dependent on what types of objects there are and thus doesn’t have to be changed when you add a new type of object. The aforementioned Singleton is classified as a creational pattern, and later in this book you’ll see examples of Factory Method and Prototype.
2. Structural: designing objects to satisfy particular project constraints. These work with the way objects are connected with other objects to ensure that changes in the system don’t require changes to those connections.
3. Behavioral: objects that handle particular types of actions within a program. These encapsulate processes that you want to perform, such as interpreting a language, fulfilling a request, moving through a sequence (as in an iterator), or implementing an algorithm. This book contains examples of the Observer and the Visitor patterns.
The Design Patterns book has a section on each of its 23 patterns along with one or more examples for each, typically in C++ (rather restricted C++, at that) but sometimes in Smalltalk. (You’ll find that this doesn’t matter too much since you can easily translate the concepts from either language into Java.) This book will revisit many of the patterns shown in Design Patterns but with a Java orientation, since the language changes the expression and understanding of the patterns. However, the GoF examples will not be repeated here, since I believe that it’s possible to produce more illuminating examples given some effort. The goal is to provide you with a decent feel for what patterns are about and why they are so important.
After years of looking at these things, it began to occur to me that the patterns themselves use basic principles of organization, other than (and more fundamental than) those described in Design Patterns. These principles are based on the structure of the implementations, which is where I have seen great similarities between patterns (more than those expressed in Design Patterns). Although we generally try to avoid implementation in favor of interface, for awhile I thought that it was easier to understand the patterns in terms of these structural principles, and tried reorganizing the book around the patterns based on their structure instead of the categories presented in Design Patterns.
However, a later insight made me realize that it’s more useful to organize the patterns in terms of the problems they solve. I believe this is a subtle but important distinction from the way Metsker organizes the patterns by intent in Design Patterns Java Workshop (Addison-Wesley 2002), because I hope that you will then be able to recognize your problem and search for a solution, if the patterns are organized this way.
In the process of doing all this “book refactoring” I realized that if I changed it once, I would probably change it again (there’s definitely a design maxim in there), so I removed all references to chapter numbers in order to facilitate this change (the little-known “numberless chapter” pattern J).HowHH
Issues of development, the UML process, Extreme Programming.
Is evaluation valuable? The Capability Immaturity Model:
Wiki Page: http://c2.com/cgi-bin/wiki?CapabilityImMaturityModel
Article: http://www.embedded.com/98/9807br.htm
Pair programming research:
http://collaboration.csc.ncsu.edu/laurie/
In an earlier version of this book I decided that unit testing was essential (for all of my books) and that JUnit was too verbose and clunky to consider. At that time I wrote my own unit testing framework using Java reflection to simplify the syntax necessary to achieve unit testing. For the third edition of Thinking in Java, we developed another unit testing framework for that book which would test the output of examples.
In the meantime, JUnit has changed to add a syntax remarkably similar to the one that I used in an earlier version of this book. I don’t know how much influence I may have had on that change, but I’m simply happy that it has happened, because I no longer feel the need to support my own system (which you can still find <some URL here>) and can simply recommend the defacto standard.
I have introduced and described the style of JUnit coding that I consider a “best practice” (primarily because of simplicity), in Thinking in Java, 3rd edition, chapter 15. That section provides an adequate introduction to any of the unit testing you will see associated with this book (however, the unit testing code will not normally be included in the text of this book). When you download the code for this book, you will find (4/9/2003: Eventually, not yet) unit tests along with the code examples whenever possible.
(From Bill):
Public: in test subdirectory; different package (don’t include in jar).
Package access: same package, subdirectory path underneath library code (don’t include in jar)
Private access: (white box testing). Nested class, strip out, or Junit addons.
Before getting into more complex techniques, it’s helpful to look at some basic ways to keep code simple and straightforward.
The most trivial of these is the messenger, which simply packages information into an object to be passed around, instead of passing all the pieces around separately. Note that without the messenger, the code for translate() would be much more confusing to read:
//: simplifying:MessengerDemo.java
package simplifying;
import junit.framework.*;
class Point { // A messenger
public int x, y, z; // Since it's just a carrier
public Point(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Point(Point p) { // Copy-constructor
this.x = p.x;
this.y = p.y;
this.z = p.z;
}
public String toString() {
return "x: " + x + " y: " + y + " z: " + z;
}
}
class Vector {
public int magnitude, direction;
public Vector(int magnitude, int direction) {
this.magnitude = magnitude;
this.direction = direction;
}
}
class Space {
public static Point translate(Point p, Vector v) {
p = new Point(p); // Don't modify the original
// Perform calculation using v. Dummy calculation:
p.x = p.x + 1;
p.y = p.y + 1;
p.z = p.z + 1;
return p;
}
}
public class MessengerDemo extends TestCase {
public void test() {
Point p1 = new Point(1, 2, 3);
Point p2 = Space.translate(p1, new Vector(11, 47));
String result = "p1: " + p1 + " p2: " + p2;
System.out.println(result);
assertEquals(result,
"p1: x: 1 y: 2 z: 3 p2: x: 2 y: 3 z: 4");
}
public static void main(String[] args) {
junit.textui.TestRunner.run(MessengerDemo.class);
}
} ///:~
Since the goal of a messenger is only to carry data, that data is made public for easy access. However, you may also have reasons to make the fields private.
Messenger’s big brother is the collecting parameter, whose job is to capture information from the method to which it is passed. Generally, this is used when the collecting parameter is passed to multiple methods, so it’s like a bee collecting pollen.
A container makes an especially useful collecting parameter, since it is already set up to dynamically add objects:
//: simplifying:CollectingParameterDemo.java
package simplifying;
import java.util.*;
import junit.framework.*;
class CollectingParameter extends ArrayList {}
class Filler {
public void f(CollectingParameter cp) {
cp.add("accumulating");
}
public void g(CollectingParameter cp) {
cp.add("items");
}
public void h(CollectingParameter cp) {
cp.add("as we go");
}
}
public class CollectingParameterDemo extends TestCase {
public void test() {
Filler filler = new Filler();
CollectingParameter cp = new CollectingParameter();
filler.f(cp);
filler.g(cp);
filler.h(cp);
String result = "" + cp;
System.out.println(cp);
assertEquals(result,"[accumulating, items, as we go]");
}
public static void main(String[] args) {
junit.textui.TestRunner.run(
CollectingParameterDemo.class);
}
} ///:~
The collecting parameter must have some way to set or insert values. Note that by this definition, a messenger could be used as a collecting parameter. The key is that a collecting parameter is passed about and modified by the methods it is passed to.
The two patterns described here are solely used to control the quantity of objects.
Singleton could actually be thought of as a special case of Object Pool, but the applications of the Object Pool tend to be uniqe enough from Singleton that it’s worth treating the two separately.
Possibly the simplest design pattern is the singleton, which is a way to provide one and only one object of a particular type. An important aspect of Singleton is that you provide a global access point, so singletons are often a solution for what you would have used a global variable for in C. In addition, a singleton often has the characteristics of a registry or lookup service – it’s a place you go to find references to other objects.
Singletons can be found in the Java libraries, but here’s a more direct example:
//: singleton:SingletonPattern.java
// The Singleton design pattern: you can
// never instantiate more than one.
package singleton;
import junit.framework.*;
// Since this isn't inherited from a Cloneable
// base class and cloneability isn't added,
// making it final prevents cloneability from
// being added through inheritance:
final class Singleton {
private static Singleton s = new Singleton(47);
private int i;
private Singleton(int x) { i = x; }
public static Singleton getReference() {
return s;
}
public int getValue() { return i; }
public void setValue(int x) { i = x; }
}
public class SingletonPattern extends TestCase {
public void test() {
Singleton s = Singleton.getReference();
String result = "" + s.getValue();
System.out.println(result);
assertEquals(result, "47");
Singleton s2 = Singleton.getReference();
s2.setValue(9);
result = "" + s.getValue();
System.out.println(result);
assertEquals(result, "9");
try {
// Can't do this: compile-time error.
// Singleton s3 = (Singleton)s2.clone();
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
junit.textui.TestRunner.run(SingletonPattern.class);
}
} ///:~
The key to creating a singleton is to prevent the client programmer from having any way to create an object except the ways you provide. You must make all constructors private, and you must create at least one constructor to prevent the compiler from synthesizing a default constructor for you (which it will create using package access).
At this point, you decide how you’re going to create your object. Here, it’s created statically, but you can also wait until the client programmer asks for one and create it on demand. In any case, the object should be stored privately. You provide access through public methods. Here, getReference( ) produces the reference to the Singleton object. The rest of the interface (getValue( ) and setValue( )) is the regular class interface.
Java also allows the creation of objects through cloning. In this example, making the class final prevents cloning. Since Singleton is inherited directly from Object, the clone( ) method remains protected so it cannot be used (doing so produces a compile-time error). However, if you’re inheriting from a class hierarchy that has already overridden clone( ) as public and implemented Cloneable, the way to prevent cloning is to override clone( ) and throw a CloneNotSupportedException as described in Appendix A of Thinking in Java, 2nd edition. (You could also override clone( ) and simply return this, but that would be deceiving since the client programmer would think they were cloning the object, but would instead still be dealing with the original.) Actually, this isn’t precisely true, because even in the above situation someone could still use reflection to invoke clone( ) [[is this true? clone( ) is still protected so I’m not so sure. If it is true, you’d have to throw CloneNotSupportedException as the only way to guarantee un-cloneability ]]
1. SingletonPattern.java always creates an object, even if it’s never used. Modify this program to use lazy initialization, so the singleton object is only created the first time that it is needed.
2. Create a registry/lookup service that accepts a Java interface and produces a reference to an object that implements that interface.
Note that you aren’t restricted to creating only one object. This is also a technique to create a limited pool of objects. In that situation, however, you can be confronted with the problem of sharing objects in the pool. If this is an issue, you can create a solution involving a check-out and check-in of the shared objects.
As an example, consider a database. Commercial databases often restrict the number of connections that you can use at any one time. Here is an implementation that uses an object pool to manage the connections. First, the basic concept of managing a pool of objects is implemented as a separate class:
//: singleton:PoolManager.java
package singleton;
import java.util.*;
public class PoolManager {
private static class PoolItem {
boolean inUse = false;
Object item;
PoolItem(Object item) { this.item = item; }
}
private ArrayList items = new ArrayList();
public void add(Object item) {
items.add(new PoolItem(item));
}
static class EmptyPoolException extends Exception {}
public Object get() throws EmptyPoolException {
for(int i = 0; i < items.size(); i++) {
PoolItem pitem = (PoolItem)items.get(i);
if(pitem.inUse == false) {
pitem.inUse = true;
return pitem.item;
}
}
// Fail early:
throw new EmptyPoolException();
// return null; // Delayed failure
}
public void release(Object item) {
for(int i = 0; i < items.size(); i++) {
PoolItem pitem = (PoolItem)items.get(i);
if(item == pitem.item) {
pitem.inUse = false;
return;
}
}
throw new RuntimeException(item + " not found");
}
} ///:~
//: singleton:ConnectionPoolDemo.java
package singleton;
import junit.framework.*;
interface Connection {
Object get();
void set(Object x);
}
class ConnectionImplementation implements Connection {
public Object get() { return null; }
public void set(Object s) {}
}
class ConnectionPool { // A singleton
private static PoolManager pool = new PoolManager();
public static void addConnections(int number) {
for(int i = 0; i < number; i++)
pool.add(new ConnectionImplementation());
}
public static Connection getConnection()
throws PoolManager.EmptyPoolException {
return (Connection)pool.get();
}
public static void releaseConnection(Connection c) {
pool.release(c);
}
}
public class ConnectionPoolDemo extends TestCase {
static {
ConnectionPool.addConnections(5);
}
public void test() {
Connection c = null;
try {
c = ConnectionPool.getConnection();
} catch (PoolManager.EmptyPoolException e) {
throw new RuntimeException(e);
}
c.set(new Object());
c.get();
ConnectionPool.releaseConnection(c);
}
public void test2() {
Connection c = null;
try {
c = ConnectionPool.getConnection();
} catch (PoolManager.EmptyPoolException e) {
throw new RuntimeException(e);
}
c.set(new Object());
c.get();
ConnectionPool.releaseConnection(c);
}
public static void main(String args[]) {
junit.textui.TestRunner.run(ConnectionPoolDemo.class);
}
} ///:~
1. Add unit tests to ConnectionPoolDemo.java to demonstrate the problem that the client may release the connection but still continue to use it.
Both Proxy and State provide a surrogate class that you use in your code; the real class that does the work is hidden behind this surrogate class. When you call a method in the surrogate, it simply turns around and calls the method in the implementing class. These two patterns are so similar that the Proxy is simply a special case of State. One is tempted to just lump the two together into a pattern called Surrogate, but the term “proxy” has a long-standing and specialized meaning, which probably explains the reason for the two different patterns.
The basic idea is simple: from a base class, the surrogate is derived along with the class or classes that provide the actual implementation:

When a surrogate object is created, it is given an implementation to which to send all of the method calls.
Structurally, the difference between Proxy and State is simple: a Proxy has only one implementation, while State has more than one. The application of the patterns is considered (in Design Patterns) to be distinct: Proxy is used to control access to its implementation, while State allows you to change the implementation dynamically. However, if you expand your notion of “controlling access to implementation” then the two fit neatly together.
If we implement Proxy by following the above diagram, it looks like this:
//: proxy:ProxyDemo.java
// Simple demonstration of the Proxy pattern.
package proxy;
import junit.framework.*;
interface ProxyBase {
void f();
void g();
void h();
}
class Proxy implements ProxyBase {
private ProxyBase implementation;
public Proxy() {
implementation = new Implementation();
}
// Pass method calls to the implementation:
public void f() { implementation.f(); }
public void g() { implementation.g(); }
public void h() { implementation.h(); }
}
class Implementation implements ProxyBase {
public void f() {
System.out.println("Implementation.f()");
}
public void g() {
System.out.println("Implementation.g()");
}
public void h() {
System.out.println("Implementation.h()");
}
}
public class ProxyDemo extends TestCase {
Proxy p = new Proxy();
public void test() {
// This just makes sure it will complete
// without throwing an exception.
p.f();
p.g();
p.h();
}
public static void main(String args[]) {
junit.textui.TestRunner.run(ProxyDemo.class);
}
} ///:~
Of course, it isn’t necessary that Implementation have the same interface as Proxy; as long as Proxy is somehow “speaking for” the class that it is referring method calls to then the basic idea is satisfied (note that this statement is at odds with the definition for Proxy in GoF). However, it is convenient to have a common interface so that Implementation is forced to fulfill all the methods that Proxy needs to call.
//: proxy:PoolManager.java
package proxy;
import java.util.*;
public class PoolManager {
private static class PoolItem {
boolean inUse = false;
Object item;
PoolItem(Object item) { this.item = item; }
}
public class ReleasableReference { // Used to build the proxy
private PoolItem reference;
private boolean released = false;
public ReleasableReference(PoolItem reference) {
this.reference = reference;
}
public Object getReference() {
if(released)
throw new RuntimeException(
"Tried to use reference after it was released");
return reference.item;
}
public void release() {
released = true;
reference.inUse = false;
}
}
private ArrayList items = new ArrayList();
public void add(Object item) {
items.add(new PoolItem(item));
}