A Little Java, A Few Patterns
FOREWORD
Learning to program is more than learning the syntactic and semantic rules of a programming
language. It also requires learning how to design programs. Any good book on programming
must therefore teach program design.
Like any other form of design, program design has competing schools. These schools are
often associated '''lith a particular set of languages. Since Java is an object-oriented programming
language, people teaching Java should emphasize object-oriented design.
Felleisen and Friedman show that the functional (input-output driven) method of program
design naturally leads to the use of well-known object-oriented design patterns. In fact, they
integrate the two styles seamlessly and show how well they work together. Their book proves that
the functional design method does not clash with, but supports object-oriented programming.
Their success doesn't surprise me, because I've seen it in Smalltalk for many years, though
unfortunately, it seems to have remained one of the secrets of object-oriented design.
I am
happy to see that Felleisen and Friedman have finally exposed it. This book will be especially
useful if you are a C++ programmer learning Java, since you probably haven't seen functional
program design before. If you know functional design, the book will gently introduce you to
pattern-based programming in Java. If you don't know it, Felleisen and Friedman ,vill teach
you a powerful new way of thinking that you should add to .your design toolbox.
Enjoy the pizzas!
Ralph E. Johnson
Champaign, Illinois
ix
Preface
An object-oriented programming language enables a programmer to construct reusable program
components. With such components, other programmers can quickly build large new programs
and program fragments. In the ideal case, the programmers do not modify any existing code
but simply glue together components and add a few new ones. This reusability of components,
however, does not come for free. It requires a well-designed object-oriented language and a strict
discipline of programming.
Java is a such a language, and this book introduces its object-oriented elements: (abstract)
classes, fields, methods, inheritance, and interfaces. This small core language has a simple
semantic model, which greatly helps programmers to express themselves.
In addition, Java
implementations automatically manage the memory a program uses, which frees programmers
from thinking about machine details and encourages them to focus on design.
The book's second goal is to introduce the reader to design patterns, the key elements of a
programming discipline that enhances code reuse. Design patterns help programmers organize
their object-oriented components so that they properly implement the desired computational
process. l\lore importantly still, design patterns help communicate important properties about
a program component. If a component is an instance of an explicitly formulated pattern and
documented as such, other programmers can easily understand its structure and reuse it in their
own programs, even without access to the component's source.
THE INTENDED AUDIENCE
The book is primarily intended for people-practicing programmers, instructors and students
alike-who wish to study the essential elements of object-oriented programming and the idea
of design patterns. Readers must have some basic programming experience. They will benefit
most from the book if they understand the principles of functional design, that is, the design
of program fragments based on their input-output behavior. An introductory computer science
course that uses Scheme (or ML) is the best way to get familiar with this style of design, but it
is not required.
WHAT THIS BOOK IS NOT ABOUT
Java provides many useful features and libraries beyond its object-oriented core. While these
additional Java elements are important for professional programming, their coverage would
distract from the book's important goals: object-oriented programming and the use of design
patterns. For that reason, this book is not a complete introduction to Java. Still, readers
who master its contents can quickly become skilled Java programmers with the supplementary
sources listed in the Commencement.
The literature on design patterns evolves quickly. Thus, there is quite a bit more to patterns
than an introductory book could intelligibly cover. Yet, the simplicity of the patterns we use
and the power that they provide should encourage readers to study the additional references
about patterns mentioned at the end of the book.
\\J'e are indebted to many people for their contributions and assistance throughout the devel
opment of this book. Several extensive discussions with Shriram Krishnamurthi, Jon Rossie,
ACKNOWLEDGMENTS
xi
and r..1itch Wand kept us on track; their detailed comments deeply influenced our thinking at
critical junctures. Michael Ashley, Sundar Balasubramaniam, Cynthia Brown, Peter Drake,
Bob Filman, Robby Findler, Steve Ganz, Paul Graunke, John Greiner, Erik Hilsdale, l\latthew
Kudzin, Julia Lawall, Shinn-Der Lee, Michael Levin, Gary McGraw, Benjamin Pierce, Amr
Sabry, Jonathan Sobel, and George Springer read the book at various stages of development and
their comments helped produce the final result. We also wish to thank Robert Prior at MIT
Press who loyally supported us for many years and fostered the idea of a "Little Java." The book
greatly benefited from Dorai Sitaram's incredibly clever Scheme typesetting program SIb-TEX.
Finally, we would like to thank the National Science Foundation for its continued support
and especially for the Educational Innovation Grant that provided us with the opportunity to
collaborate for the past year.
READING GUIDELINES
Do not rush through this book. Allow seven sittings, at least. Read carefully. Mark up the book
or take notes; valuable hints are scattered throughout the text. Work through the examples,
don't scan them. Keep in mind the motto "Think first, experiment later."
The book is a dialogue about interesting Java programs. After you have understood the
examples, experiment with them, that is, modify the programs and examples and see how they
behave. Since most Java implementations are unfortunately batch interpreters or compilers, this
requires work of a repetitive nature on your side. Some hints on how to experiment with Java
are provided on the following pages.
\Ve do not give any formal definitions in this book. V·le believe that you can form your own
definitions and thus remember and understand them better than if we had written them out for
you. But be sure you know and understand the bits of advice that appear in most chapters.
\Ve use a few notational conventions throughout the text to help you understand the
programs on several levels. The primary conventions concern typeface for different kinds of
words. Field and method names are in italic. Basic data, including numbers, booleans, and
constructors introduced via datatypes are set in sans serif. Keywords, e.g., class, abstract,
return and interface are in boldface. When you experiment, you may ignore the typefaces
but not the related framenotes. To highlight this role of typefaces, the programs in framenotes
are set in a typewriter face.
Food appears in many of our examples for two reasons. First, food is easier to visualize
than abstract ideas. (This is not a good book to read while dieting.) \Ve hope the choice of
food will help you understand the examples and concepts we use. Second, we want to provide
you with a little distraction. We know how frustrating the subject matter can be, and a little
distraction \vill help you keep your sanity.
You are now ready to start. Good luck! We hope you will enjoy the experiences waiting for
you on the following pages.
xii
Bon appetit!
Matthias Felleisen
Daniel P. Friedman
EXPERIMENTING WITH JAVA
Here are some hints on how to experiment with Java: 1
1. Create a file that contains a complete hierarchy of classes.
2. To each class whose name does not end with a superscript V, V, I, or M, add a toString
method according to these rules:
a) if the class does not contain any fields, use
public String toString() {
return "new II + getClass 0 . get Name 0 + II 0 "; }
b) if the class has one field, say x, use
public String toString() {
return "new II + getClassO . get Name 0 + II ( " + X + ") "; }
c) if the class has two fields, say x and y, use
public String toString() {
return "new II + getClassO . get Name 0 + II ( " + x + II
II + Y + ") "; }
3. Add the following class at the bottom of the file:
class Main {
public static void main(String args( ]) {
DataType_or_Interface y = new _____ •
System.out.println( ...... ); } }
With DataType_or _Interface y = new _____ , create the object y with which you wish to
experiment. Then replace ...... with the example expression that you would like to experiment
with. For example, if you wish to experiment with the distanceToO method of ManhattanPt
as defined in chapter 2, add the following definition to the end of your file:
class Main {
public static void main(String args( ]) {
PointD y = new ManhattanPt(2,8)j
System.out.println( y.distanceToO() ); } }
lSee Arnold and Gosling (IJ for details on how they work. These hints make little sense out of context, so for
now, just follow them as you read this book.
xiii
If you wish to experiment with a sequence of expressions that modify y, as in chapter ]0, e.g.,
y.
y.
y.- -
replace . . . . . . with
y.
y.
y.-
+ "\n " +
+ "\n " +
For example, if you wish to experiment with the methods of PiemanM as defined in chapter 10,
add the following definition to the end of your file:
class Main {
public static void main(String args[ ]) {
PiemanI y = new PiemanM();
System.out.println(
y. addTop(new Anchovy 0 ) + "\n" +
y. addTop(new Anchovy 0 ) + "\n" +
y.substTop(new Tuna() ,new Anchovy()) ); } }
4. Finally, compile the file and interpret the class Main.
xiv
flo
~(rv&C9IT~tll ~~