Welcome To Design Patterns - Intro To Design Patterns - Head First Design Patterns, 2nd Edition
Welcome To Design Patterns - Intro To Design Patterns - Head First Design Patterns, 2nd Edition
Joe works for a company that makes a highly successful duck pond simu‐
lation game, SimUDuck. The game can show a large variety of duck
species swimming and making quacking sounds. The initial designers of
the system used standard OO techniques and created one Duck superclass
from which all other duck types inherit.
In the last year, the company has been under increasing pressure from
competitors. After a week-long off-site brainstorming session over golf,
the company executives think it’s time for a big innovation. They need
something really impressive to show at the upcoming shareholders meet‐
ing in Maui next week.
The executives decided that flying ducks is just what the simulator needs
to blow away the competitors. And of course Joe’s manager told them it’ll
be no problem for Joe to just whip something up in a week. “After all,”
said Joe’s boss, “he’s an OO programmer…how hard can it be?”
But something went horribly wrong...
What happened?
Joe failed to notice that not all subclasses of Duck should fly. When Joe
added new behavior to the Duck superclass, he was also adding behavior
that was not appropriate for some Duck subclasses. He now has flying
inanimate objects in the SimUDuck program.
A localized update to the code caused a non-local side effect (flying rubber
ducks)!
What Joe thought was a great use of inheritance for the pur‐
pose of reuse hasn’t turned out so well when it comes to main‐
tenance.
Joe realized that inheritance probably wasn’t the answer, because he just
got a memo that says that the executives now want to update the product
every six months (in ways they haven’t yet decided on). Joe knows the
spec will keep changing and he’ll be forced to look at and possibly over‐
ride fly() and quack() for every new Duck subclass that’s ever added to
the program... forever.
So, he needs a cleaner way to have only some (but not all) of the duck
types fly or quack.
We know that not all of the subclasses should have flying or quacking be‐
havior, so inheritance isn’t the right answer. But while having the sub‐
classes implement Flyable and/or Quackable solves part of the problem
(no inappropriately flying rubber ducks), it completely destroys code re‐
use for those behaviors, so it just creates a different maintenance night‐
mare. And of course there might be more than one kind of flying behav‐
ior even among the ducks that do fly...
At this point you might be waiting for a Design Pattern to come riding in
on a white horse and save the day. But what fun would that be? No, we’re
going to figure out a solution the old-fashioned way—by applying good OO
software design principles.
The one constant in software
development
Okay, what’s the one thing you can always count on in software
development?
No matter where you work, what you’re building, or what language you
are programming in, what’s the one true constant that will be with you
always?
Lots of things can drive change. List some reasons you’ve had to change
code in your applications (we put in a couple of our own to get you start‐
ed). Check your answers with the solution at the end of the chapter be‐
fore you go on.
_____________________________________________________________________
_____________________________________________________________________
_____________________________________________________________________
_____________________________________________________________________
_____________________________________________________________________
So we know using inheritance hasn’t worked out very well, since the duck
behavior keeps changing across the subclasses, and it’s not appropriate
for all subclasses to have those behaviors. The Flyable and Quackable in‐
terface sounded promising at first—only ducks that really do fly will be
Flyable, etc.—except Java interfaces typically have no implementation
code, so no code reuse. In either case, whenever you need to modify a be‐
havior, you’re often forced to track down and change it in all the different
subclasses where that behavior is defined, probably introducing new
bugs along the way!
Here’s another way to think about this principle: take the parts that
vary and encapsulate them, so that later you can alter or extend the
parts that vary without affecting those that don’t.
As simple as this concept is, it forms the basis for almost every design pat‐
tern. All patterns provide a way to let some part of a system vary indepen‐
dently of all other parts.
Okay, time to pull the duck behavior out of the Duck classes!
Where do we start? As far as we can tell, other than the problems with
fly() and quack(), the Duck class is working well and there are no other
parts of it that appear to vary or change frequently. So, other than a few
slight changes, we’re going to pretty much leave the Duck class alone.
Now, to separate the “parts that change from those that stay the same,”
we are going to create two sets of classes (totally apart from Duck), one
for fly and one for quack. Each set of classes will hold all the implementa‐
tions of the respective behavior. For instance, we might have one class
that implements quacking, another that implements squeaking, and anoth‐
er that implements silence.
We know that fly() and quack() are the parts of the Duck class
that vary across ducks.
To separate these behaviors from the Duck class, we’ll pull both
methods out of the Duck class and create a new set of classes to
represent each behavior.
So how are we going to design the set of classes that implement the
fly and quack behaviors?
We’d like to keep things flexible; after all, it was the inflexibility in the
duck behaviors that got us into trouble in the first place. And we know
that we want to assign behaviors to the instances of Duck. For example,
we might want to instantiate a new MallardDuck instance and initialize it
with a specific type of flying behavior. And while we’re there, why not
make sure that we can change the behavior of a duck dynamically? In
other words, we should include behavior setter methods in the Duck
classes so that we can change the MallardDuck’s flying behavior at
runtime.
So this time it won’t be the Duck classes that will implement the flying
and quacking interfaces. Instead, we’ll make a set of classes whose entire
reason for living is to represent a behavior (for example, “squeaking”),
and it’s the behavior class, rather than the Duck class, that will implement
the behavior interface.
This is in contrast to the way we were doing things before, where a be‐
havior came either from a concrete implementation in the superclass
Duck, or by providing a specialized implementation in the subclass itself.
In both cases we were relying on an implementation. We were locked into
using that specific implementation and there was no room for changing
the behavior (other than writing more code).
With our new design, the Duck subclasses will use a behavior represent‐
ed by an interface (FlyBehavior and QuackBehavior), so that the actual
implementation of the behavior (in other words, the specific concrete be‐
havior coded in the class that implements the FlyBehavior or
QuackBehavior) won’t be locked into the Duck subclass.
From now on, the Duck behaviors will live in a separate class—
a class that implements a particular behavior interface.
That way, the Duck classes won’t need to know any of the imple‐
mentation details for their own behaviors.
A: Not always; often when you are designing an application, you antici‐
pate those areas that are going to vary and then go ahead and build the
flexibility to deal with it into your code. You’ll find that the principles and
patterns can be applied at any stage of the development lifecycle.
A: Not in this case. As you’ll see once we’ve got everything hooked togeth‐
er, we do benefit by having Duck not be an interface, and having specific
ducks, like MallardDuck, inherit common properties and methods. Now
that we’ve removed what varies from the Duck inheritance, we get the
benefits of this structure without the problems.
Q: It feels a little weird to have a class that’s just a behavior. Aren’t
classes supposed to represent things? Aren’t classes supposed to have
both state AND behavior?
1. Using our new design, what would you do if you needed to add rock‐
et-powered flying to the SimUDuck app?
2. Can you think of a class that might want to use the Quack behavior
that isn’t a duck?
Answers:
NOTE
Here’s the key: A Duck will now delegate its flying and quacking behaviors,
instead of using quacking and flying methods defined in the Duck class (or
subclass).
Here’s how:
Pretty simple, huh? To perform the quack, a Duck just asks the object
that is referenced by quackBehavior to quack for it. In this part of
the code we don’t care what kind of object the concrete Duck is, all
we care about is that it knows how to quack()!
More integration...
1. Type and compile the Duck class below (Duck.java), and the
MallardDuck class from two pages back (MallardDuck.java).
What a shame to have all this dynamic talent built into our ducks and not
be using it! Imagine you want to set the duck’s behavior type through a
setter method on the Duck class, rather than by instantiating it in the
duck’s constructor.
5. Run it!
Okay, now that we’ve done the deep dive on the duck simulator de‐
sign, it’s time to come back up for air and take a look at the big
picture.
Notice also that we’ve started to describe things a little differently. Instead
of thinking of the duck behaviors as a set of behaviors, we’ll start thinking
of them as a family of algorithms. Think about it: in the SimUDuck design,
the algorithms represent things a duck would do (different ways of
quacking or flying), but we could just as easily use the same techniques
for a set of classes that implement the ways to compute state sales tax by
different states.
Pay careful attention to the relationships between the classes. In fact, grab
your pen and write the appropriate relationship (IS-A, HAS-A, and
IMPLEMENTS) on each arrow in the class diagram.
NOTE
When you put two classes together like this you’re using composition.
Instead of inheriting their behavior, the ducks get their behavior by be‐
ing composed with the right behavior object.
Composition is used in many design patterns and you’ll see a lot more
about its advantages and disadvantages throughout the book.
BRAIN POWER
A duck call is a device that hunters use to mimic the calls (quacks) of
ducks. How would you implement your own duck call that does not inher‐
it from the Duck class?
GURU AND STUDENT
Student: Guru, I have learned that the promise of the object-oriented way
is reuse.
Guru: Continue...
Student: Guru, through inheritance all good things may be reused and so
we come to drastically cut development time like we swiftly cut bamboo in
the woods.
Student: The answer is after, Guru. We always spend more time maintain‐
ing and changing software than on initial development.
Guru: I can see that you still have much to learn. I would like for you to go
and meditate on inheritance further. As you’ve seen, inheritance has its
problems, and there are other ways of achieving reuse.
Speaking of Design Patterns...
You just applied your first design pattern—the STRATEGY Pattern. That’s
right, you used the Strategy Pattern to rework the SimUDuck app.
Thanks to this pattern, the simulator is ready for any changes those execs
might cook up on their next business trip to Maui.
Now that we’ve made you take the long road to learn it, here’s the formal
definition of this pattern:
NOTE
The Strategy Pattern defines a family of algorithms, encapsulates each one, and
makes them interchangeable. Strategy lets the algorithm vary independently from
clients that use it.
NOTE
Use THIS definition when you need to impress friends and influence key
executives.
Design Puzzle
Below you’ll find a mess of classes and interfaces for an action adventure
game. You’ll find classes for game characters along with classes for
weapon behaviors the characters can use in the game. Each character can
make use of one weapon at a time, but can change weapons at any time
during the game. Your job is to sort it all out...
What’s the difference between these two orders? Not a thing! They’re
both the same order, except Alice is using twice the number of words and
trying the patience of a grumpy short-order cook.
What’s Flo got that Alice doesn’t? A shared vocabulary with the short-or‐
der cook. Not only does that make it easier to communicate with the cook,
but it gives the cook less to remember because he’s got all the diner pat‐
terns in his head.
Can you think of other shared vocabularies that are used beyond OO de‐
sign and diner talk? (Hint: how about auto mechanics, carpenters,
gourmet chefs, and air traffic controllers?) What qualities are communi‐
cated along with the lingo?
Can you think of aspects of OO design that get communicated along with
pattern names? What qualities get communicated along with the name
“Strategy Pattern”?
When you communicate using patterns, you are doing more than just
sharing LINGO.
NOTE
“We’re using the Strategy Pattern to implement the various behaviors of our
ducks.” This tells you the duck behavior has been encapsulated into its own set of
classes that can be easily expanded and changed, even at runtime if needed.
Patterns allow you to say more with less. When you use a pattern in a
description, other developers quickly know precisely the design you have
in mind.
Talking at the pattern level allows you to stay “in the design” longer.
Talking about software systems using patterns allows you to keep the dis‐
cussion at the design level, without having to dive down to the nitty-gritty
details of implementing objects and classes.
NOTE
How many design meetings have you been in that quickly degrade into imple‐
mentation details?
NOTE
As your team begins to share design ideas and experience in terms of patterns,
you will build a community of pattern users.
NOTE
Think about starting a patterns study group at your organization. Maybe you can
even get paid while you’re learning...
Design patterns don’t go directly into your code, they first go into your
BRAIN. Once you’ve loaded your brain with a good working knowledge of
patterns, you can then start to apply them to your new designs, and re‐
work your old code when you find it’s degrading into an inflexible mess.
A: Design patterns are higher level than libraries. Design patterns tell us
how to structure classes and objects to solve certain problems, and it is
our job to adapt those designs to fit our particular application.
A: Frameworks and libraries are not design patterns; they provide specif‐
ic implementations that we link into our code. Sometimes, however, li‐
braries and frameworks make use of design patterns in their implemen‐
tations. That’s great, because once you understand design patterns, you’ll
more quickly understand APIs that are structured around design
patterns.
A: No, but you will learn later about patterns catalogs with lists of pat‐
terns that you can apply to your applications.
Developer: Okay, hmm, but isn’t this all just good object-oriented design;
I mean as long as I follow encapsulation and I know about abstraction, in‐
heritance, and polymorphism, do I really need to think about Design
Patterns? Isn’t it pretty straightforward? Isn’t this why I took all those OO
courses? I think Design Patterns are useful for people who don’t know
good OO design.
Developer: No?
Guru: No. As it turns out, constructing OO systems that have these prop‐
erties is not always obvious and has been discovered only through hard
work.
Developer: So, by knowing patterns, I can skip the hard work and jump
straight to designs that always work?
Guru: Yes, to an extent, but remember, design is an art. There will always
be tradeoffs. But, if you follow well-thought-out and time-tested design
patterns, you’ll be way ahead.
You’ve nearly made it through the first chapter! You’ve already put a few
tools in your OO toolbox; let’s make a list of them before we move on to
Chapter 2.
BULLET POINTS
It’s your standard crossword; all of the solution words are from this
chapter.
ACROSS
8. Development constant.
DOWN
2. Patterns go into your _______.
Character is the abstract class for all the other characters (King, Queen,
Knight, and Troll), while WeaponBehavior is an interface that all weapon
behaviors implement. So all actual characters and weapons are concrete
classes.
Note that ANY object could implement the WeaponBehavior interface—say, a pa‐
per clip, a tube of toothpaste, or a mutated sea bass.
What are some factors that drive change in your applications? You might
have a very different list, but here’s a few of ours. Look familiar? Here’s
our solution.
Well, technology changes and we’ve got to update our code to make use of
protocols.
We’ve learned enough building our system that we’d like to go back and
do things a little better.
Design Patterns Crossword
Solution