Head First Design Patterns ch03.pdf

(1505 KB) Pobierz
chapter3NewNew.indd
356835247.008.png
3 the DecoratorPattern
h
g
Decorating Objects
g
I used to think real men
subclassed everything. That was
until I learned the power of
extension at runtime, rather than
at compile time. Now look at me!
Just call this chapter “Design Eye for the Inheritance Guy.”
We’ll re-examine the typical overuse of inheritance and you’ll learn how to decorate
your classes at runtime using a form of object composition. Why? Once you know the
techniques of decorating, you’ll be able to give your (or someone else’s) objects new
responsibilities without making any code changes to the underlying classes.
this is a new chapter 79
356835247.009.png 356835247.010.png
the starbuzz story
Welcome to Starbuzz Coffee
Starbuzz Coffee has made a name for itself as the
fastest growing coffee shop around. If you’ve seen one
on your local corner, look across the street; you’ll see
another one.
Because they’ve grown so quickly, they’re scrambling
to update their ordering systems to match their
beverage offerings.
When they first went into business they designed their
classes like this...
Beverage
is s et in e ach su bclass and ho lds a
description
des criptio n of t he bev erage, like
The c ost() meth od is
abstr act; s ubclas sses
need to de fine t heir
own i mplem entat ion.
“Mo st Ex cellent Dark Roast ”.
The getDes criptio n() me thod
retur ns the descr iption.
getDescription()
cost()
// Other useful methods...
HouseBlend
DarkRoast
Decaf
Espresso
cost()
cost()
cost()
cost()
Each subclas s implements cost() to return th e cost of the beverage.
80 Chapter 3
The descr iption instan ce var iable
356835247.011.png 356835247.001.png 356835247.002.png
the decorator pattern
In addition to your coffee, you can also ask for several condiments like
steamed milk, soy, and mocha (otherwise known as chocolate), and have
it all topped off with whipped milk. Starbuzz charges a bit for each of
these, so they really need to get them built into their order system.
Here’s their first attempt...
Beverage
description
getDescription()
cost()
// Other useful methods...
HouseBlendWithSteamedMilk
andMocha
DarkRoastWithSteamedMilk
andMocha
DecafWithSteamedMilk
andMocha
EspressoWithSteamedMilk
andMocha
HouseBlendWithSteamedMilk
andCaramel
cost()
cost()
cost()
cost()
HouseBlendWithWhipandMocha
EspressoWithSteamedMilk
andCaramel
cost()
DecafWithSteamedMilk
andCaramel
DarkRoastWithSteamedMilk
andCaramel
cost()
cost()
EspressoWithWhipandMocha
HouseBlendWithMocha
cost()
DarkRoastWithWhipandMocha
cost()
DecafWithWhipandMocha
HouseBlendWithSoyandMocha
cost()
EspressoWithMocha
HouseBlendWithSteamedMilk
andSoy
cost()
DarkRoastWithMocha
cost()
DecafWithMocha
cost()
cost()
EspressoWithSteamedMilk
andSoy
DecafWithSoy
HouseBlendWithSoy
cost()
cost()
cost()
DecafWithSteamedMilk
andSoy
HouseBlendWithSteamedMilk
cost()
DarkRoastWithSteamedMilk
andSoy
cost()
EspressoWithSteamedMilk
cost()
cost()
HouseBlendWithWhip
cost()
DarkRoastWithSoy
cost()
DecafWithSteamedMilk
cost()
DarkRoastWithSteamedMilk
DecafWithSoyandMocha
DarkRoastWithSoyandMocha
DarkRoastWithSoy
cost()
cost()
DecafWithSoy
cost()
cost()
HouseBlendWithSteamedMilk
andWhip
cost()
DecafWithSoyandMocha
EspressoWhip
cost()
cost()
cost()
HouseBlendWithWhipandSoy
cost()
DarkRoastWithWhip
DecafWithWhip
cost()
cost()
cost()
cost()
EspressoWithSteamedMilk
andWhip
cost()
DecafWithSteamedMilk
andWhip
DarkRoastWithSteamedMilk
andWhip
EspressoWithWhipandSoy
cost()
DarkRoastWithWhipandSoy
cost()
DecafWithWhipandSoy
cost()
cost()
cost()
cost()
Whoa!
Can you say
“class explosion?”
you are here 4 81
cost()
356835247.003.png
violating design principles
A
brain
power
It’s pretty obvious that Starbuzz has created a maintenance nightmare for
themselves. What happens when the price of milk goes up? What do they do
when they add a new caramel topping?
Thinking beyond the maintenance problem, which of the design principles that
we’ve covered so far are they violating?
This is stupid; why do we need
all these classes? Can’t we just use
instance variables and inheritance in
the superclass to keep track of the
condiments?
Well, let’s give it a try. Let’s start with the Beverage base
class and add instance variables to represent whether or
not each beverage has milk, soy, mocha and whip...
Beverage
description
milk
soy
mocha
whip
New boolean va lues for
each condiment .
Now we’ll implem ent cost() in Beverage (instead of
keeping it abstr act), so that it can calculate the
costs associated with the condiments for a partic ular
beverage instanc e. Subclasses will still override
cost(), but they will also invoke the super version so
that they can c alculate the total cost of the ba sic
beverage plus th e costs of the added condiments.
getDescription()
cost()
hasMilk()
setMilk()
hasSoy()
setSoy()
hasMocha()
setMocha()
hasWhip()
setWhip()
// Other useful methods..
82 Chapter 3
356835247.004.png 356835247.005.png 356835247.006.png 356835247.007.png
Zgłoś jeśli naruszono regulamin