Hands-On Design Patterns Slides
Hands-On Design Patterns Slides
Setup
time…
Registering
and
signing
in…
Grouping?
Environment?
Notebooks?
All
set?
1
9/22/11
Goals
Before...
+ =
A problem... Your brain A solution
After...
+ + =
A problem... Your brain A better solution
Design Patterns
FEUP ● Nuno Flores ●
3
2
9/22/11
OO
Basics
Object-‐oriented
Design
• Ok,
and
programming…eventually
3
9/22/11
SimUDuck
Duck
pond
simulation
game
• Showing
a
large
variety
of
duck
species
swimming
and
making
quacking
sounds.
Duck
quack()
swim()
display()
//OTHER duck-like methods
MallardDuck RedheadDuck
Other types of
display() { display() { ducks that inherit
// looks like a mallard } // looks like a redhead } from the Duck class
SimUDuck
But
now
we
need
ducks
to
fly…
Duck
All subclasses quack()
inherit fly(). swim()
display()
fly()
//OTHER duck-like methods
MallardDuck RedheadDuck
Other types of
display() { display() { ducks that inherit
// looks like a mallard } // looks like a redhead } from the Duck class
4
9/22/11
SimUDuck
Rubber
ducks
flying!!!
Oooppss!!
Duck
All subclasses
inherit fly(), quack()
including those swim()
who shoudn’t. display()
fly()
//OTHER duck-like methods
SimUDuck
What
happened?
• Use
of
inheritance
-‐ Good
for
reuse.
RubberDuck
-‐ Bad
for
maintenance.
quack() { // squeak}
display() { // rubberduck}
Alternatives?
fly() {
// override to do
• Override
fly()
method.
nothing
}
Other
consequences
• What
if
we
want
to
add
wooden
decoy
ducks?
DecoyDuck
quack() {
// override to do nothing
}
display() { // decoy duck}
fly() {
// override to do nothing
}
FEUP ● Nuno Flores ●
10
5
9/22/11
SimUDuck
How
about
an
interface?
Duck
Quackable
swim()
quack()
Flyable display()
//OTHER duck-like methods
fly()
SimUDuck
Can
you
say
“duplicate
code”?
• What
if
we
need
to
change
the
flying
behaviour
(in
all
the
48
duck
subclasses)?
So
what
now?
• Inheritance
not
the
answer
-‐ Not
all
of
the
duck
subclasses
“fly”
ou
“quack”
• Interfaces
destroys
code
reuse
-‐ Solves
rubber
ducks
flying…
-‐ But
creates
a
maintenance
nightmare.
6
9/22/11
Axiom
What
is
the
one
thing
you
can
always
count
on
in
software
development?
• Independent
of
the
programming
language…
• Independent
of
the
problem
domain…
• Independent
of
the
task
at
hand…
• Independent
of
where
you
work…
CHANGE
No
matter
how
well
you
design
na
application,
over
time
an
application
must
grow
and
change
or
it
will
die.
The
result?
• Fewer
unintended
consequences
from
code
changes
and
more
flexibility
in
your
systems.
SimUDuck
• fly()
and
quack()
vary
across
ducks
• Pull
methods
out
of
Duck
class
and
create
new
set
of
classes
to
represent
each
behaviour.
7
9/22/11
REUSE
• Everyone
besides
“ducks”
can
use
the
behaviours.
• We
can
add
new
behaviours
without
touching
anything.
• All
of
this
without
the
inheritance
baggage.
<<interface>>
<<interface>> QuackBehaviour
FlyBehaviour
quack()
fly()
Duck
Integrating
changes…
FlyBehaviour flyBehaviour
QuackBehaviour quackBehaviour
performQuack()
1. Add
behaviour
holders
swim()
display()
performFly()
2. Implement
performQuack()
//OTHER duck-like methods
public class Duck {
QuackBehavior quackBehavior;
// more
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
8
9/22/11
performQuack()
public void setFlyBehavior (FlyBehavior fb) { swim()
flyBehavior = fb; display()
} performFly()
public void setQuackBehavior(QuackBehavior qb) { setFlyBehaviour()
quackBehavior = qb; setQuackBehaviour()
} //OTHER duck-like methods
model.performFly();
model.setFlyBehavior(new FlyRocketPowered());
model.performFly();
}
}
5. Run
it!
%java MiniDuckSimulator
Quack
I’m flying
I can’t fly
I’m flying with a rocket
FEUP ● Nuno Flores ●
18
9
9/22/11
Family of
algorithms
FlyWithWings FlyNoWay
fly() { fly() {
// implements duck flying // do nothing - can’t fly
} }
Duck
<<interface>>
FlyBehaviour flyBehaviour QuackBehaviour
QuackBehaviour quackBehaviour quack()
performQuack()
swim()
display()
performFly()
Quack Squeak MuteQuack
setFlyBehaviour()
setQuackBehaviour() quack() { quack() { quack() {
//OTHER duck-like methods // duck quacking // rubber duck squeak // can’t quack
} } }
10
9/22/11
Design
Puzzle
Each
character
can
make
use
of
one
weapon
at
a
time.
A
character
can
change
weapons
at
any
time
during
the
game.
11
9/22/11
A
shared
vocabulary…
Shared
pattern
vocabularies
are
POWERFUL.
• Its
the
lingo,
man…
Talking
at
the
pattern
level
allows
you
to
stay
“in
the
design”
for
longer.
• How
many
design
meetings
have
you
been
in
that
quicly
degrade
into
implementation
details?
Don’t
forget…
Design
Patterns
are
more
than
good
OO
design
principles
Knowing
the
OO
Basics
doesn’t
make
you
a
good
designer.
A
design
guru
thinks
about
how
to
create
flexible
designs
that
are
maintainable
and
can
cope
with
change.
12
9/22/11
Design
Billboard
OO Ba
sics!
Abstr
action
!
Encap
sulatio
OO Principles! Polym n!
es a orphis
defin hms, m!
egy - t Inherit
Strat y of algori h one, and
Encapsulate what varies.! ance!
Favor composition over inheritance.! famil sulates eac
encap s them tegy
. Stra
Program to interfaces, not make hangeable vary
implementations.! interc e algorithmrom clients
lets thendently f
indep se it.!
that u
Challenge
Now
Ducks
can
dive.
• What
would
that
change?
13
9/22/11
WeatherData
Humidity object
sensor device
pulls data displays
Temperature
sensor device
WEATHER STATION
Our
job
• Implement
measurementsChanged()
so
that
it
updates
the
three
displays
for
current
conditions,
weather
stats,
and
forecast.
14
9/22/11
}
// other WeatherData methods here…
}
15
9/22/11
CurrentConditionsDisplay
update()
subject display() { // display current
WeatherData measurements
}
registerObserver()
removeObserver()
notifyObservers() subject
StatisticsDisplay
getTemperature()
getHumidity() subject update()
getPressure() display() { // display
measurementsChanged() measurements statistics
}
subject
ForecastDisplay
update()
display() { // display the
forecast
}
ThirdPartyDisplay
update()
display() { // display other
measurement related values
}
16
9/22/11
CurrentConditionsDisplay
Interface
classes
update()
subject display() { // display current
WeatherData measurements
}
registerObserver()
removeObserver()
notifyObservers() subject
StatisticsDisplay
getTemperature()
getHumidity() subject update()
getPressure() display() { // display
measurementsChanged() measurements statistics
}
subject
ForecastDisplay
CurrentConditionsDisplay
registerObserver()
subject
update()
display() { // display current
measurements
}
ForecastDisplay
ThirdPartyDisplay
update()
public WeatherData() {
display() { // display other
measurement related values
}
17
9/22/11
update()
display() { // display current
}
WeatherData measurements
}
registerObserver()
removeObserver()
notifyObservers() subject
StatisticsDisplay
}
getTemperature()
getHumidity() subject update()
getPressure() display() { // display
measurementsChanged() measurements statistics
}
subject
ForecastDisplay
update()
display() { // display the
forecast
}
ThirdPartyDisplay
update()
display() { // display other
measurement related values
}
CurrentConditionsDisplay
update()
subject display() { // display current
WeatherData measurements
}
registerObserver()
removeObserver()
notifyObservers() subject
StatisticsDisplay
getTemperature()
getHumidity() subject update()
getPressure() display() { // display
measurementsChanged() measurements statistics
}
subject
ForecastDisplay
update()
display() { // display the
forecast
}
ThirdPartyDisplay
update()
display() { // display other
measurement related values
}
18
9/22/11
notifications GeneralDisplay
-‐ o
=
subject
-‐ arg
=
passed
through
notifyObservers
or
null
public WeatherData() { }
19
9/22/11
20
9/22/11
21
9/22/11
Starbuzz
Coffee
Famous
fast-‐growing
coffee
shop
Initial
design
Beverage
description
getDescription()
cost()
Starbuzz
Coffee
You
can
also
ask
for
condiments
(steamed
milk,
soy,
“mocha”)
all
topped
with
whipped
milk.
Each
one
has
cost
increments.
Can
you
say
“class
explosion”?
Beverage
description
getDescription()
cost()
HouseBlendWithSteamedMilk
andMocha
DarkRoastWithSteamedMilka EspressoWithSteamedMilkan
cost() dMocha
ndMocha
cost() cost()
DecafWithSteamedMilkandCa EspressoWithSteamedMilkan
DarkRosWithSteamedMilkand ramel dMocha
HouseBlendWithWhip
Caramel
cost() cost()
cost() cost()
cost() cost()
few missing… cost()
DarkRoastWithSteamedMilka DecafWithWhip
HouseBlendWithSoyAndMoc ndMocha
ha cost()
cost()
cost()
DarkRoastWithSoyAndMocha DecaftWithSoyAndMocha
DarkRoastWithSoy
cost() cost() FEUP ● Nuno Flores ●
cost() 44
22
9/22/11
Starbuzz
Coffee
One
way
of
solving
things…
Beverage
description new boolean for
milk each condiment
soy
mocha
whip
Starbuzz
Coffee
Implemented
would
look
like…
public class Beverage {
// instance variable milkCost, soyCost, mochaCost and whipCost.
public float cost() {
public DarkRoast() {
description = “Most Excellent Dark Roast”;
}
23
9/22/11
Starbuzz
Coffee
Design
impacts
• Price
changes
for
condiments
-‐ Force
to
alter
existing
code.
• New
condiments
-‐ Force
to
add
new
methods
and
alter
the
cost
method
in
the
superclass.
• New
beverages
-‐ Some
condiment
may
not
be
appropriate
(iced
tea
with
mocha???).
-‐ Subclasses
will
inherit
superflous
code.
• What
if
a
customer
wants
a
double
mocha?
24
9/22/11
cost()
3. Decorate
it
with
a
Whip
object
cost()
Mocha
4. Call
the
cost()
method
and
rely
on
Decorator. It is the same type
as DarkRoast (Beverage)
DarkRoast
cost() cost() cost()
Mocha
Whip
DECORATOR
pattern
h
Attac sibilities
Decorators
have
the
same
supertype
as
the
object
they
ator - n
Decor onal respo mically.
decorate.
i a
addit object dyn e flexible
• We
can
pass
a
decorated
object
in
place
of
the
original
(wrapped)
to an tors provid classing
a b
object
Decor ative to su
a l t e r n n g
tendi
Objects
can
be
decorated
at
anytime
for ex ionality.!
fu n c t
• At
runtime
with
as
many
as
we
want.
25
9/22/11
Beverage
description
getDescription()
cost() component
// other useful methods
HouseBlend DarkRoast
CondimentDecorator
cost() cost()
getDescription()
Decaf Espresso
cost() cost()
Beverage
description
getDescription()
HouseBlend DarkRoast
CondimentDecorator
cost() cost()
getDescription()
Decaf Espresso
cost() cost()
Base
classes
cost() cost() cost() cost()
getDescription() getDescription() getDescription() getDescription()
26
9/22/11
Beverage
description
getDescription()
HouseBlend DarkRoast
CondimentDecorator
cost() cost()
getDescription()
Decaf Espresso
cost() cost()
public Espresso() {
description = "Espresso";
}
public HouseBlend() {
description = "House Blend Coffee";
}
Beverage
description
getDescription()
HouseBlend DarkRoast
CondimentDecorator
cost() cost()
getDescription()
Decaf Espresso
cost() cost()
27
9/22/11
Design
Challenge
Starbuzz
coffees
now
have
sizes.
• “tall”
(small)
• “grande”
(medium)
• “venti”
(large)
They
would
like
the
condiments
to
be
charged
according
to
size
• Ex:
Mocha
costa
.10,
.15,
.20
respectively
for
tall,
grande
and
venti
coffees.
What
modifications
in
the
decorator
classes
would
you
do
to
handle
these
new
requirements?
(really
do
it
)
28
9/22/11
Downsides
• Watch
out
for
large
number
of
subclasses
-‐ Can
become
overwhelming
• Keep
it
in
perspective
29
9/22/11
Pizza
Shop
Imagine
a
pizza
shop
where
you
might
order
pizzas…
Pizza orderPizza() {
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
Pizza pizza;
if (type.equals(“cheese”)) {
pizza = new CheesePizza();
} else if (type.equals(“greek”)) {
pizza = new GreekPizza();
} else if (type.equals(“pepperoni”)) {
pizza = new PepperoniPizza();
}
pizza.prepare();
. . .
} FEUP ● Nuno Flores ●
59
Pizza
Shop
But
the
pressure
is
on
to
add
more
pizza
types
Pizza orderPizza() {
pizza.prepare();
What stays pizza.bake();
the same pizza.cut();
pizza.box();
return pizza;
}
30
9/22/11
Solution:
Building
a
framework
for
the
pizza
store
and
let
the
subclasses
decide.
31
9/22/11
return pizza;
We’ve moved our factory
abstract Pizza createPizza(String type); object to this method
}
Our “factory method” is now
abstract in PizzaStore
PizzaStore
createPizza()
orderPizza()
Making
a
PizzaStore
NewYork
style
pizza
store
NYPizzaStore extends PizzaStore,
so it inherits the orderPizza()
createPizza() return a Pizza, and method (among others)
the subclass if fully responsible for
which concrete Pizza it
instantiates
public class NYPizzaStore extends PizzaStore {
Note:
• orderPizza()
method
in
the
superclass
has
no
clue
which
Pizza
we
are
creating.
It
just
knows
it
can
prepare,
bake,
cut
and
box
it!
32
9/22/11
void prepare() {
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for (int i = 0; i < toppings.size(); i++) {
System.out.println(" " + toppings.get(i));
}
}
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
name
dough
public NYStyleCheesePizza() { sauce
toppings
prepare()
name = "NY Style Sauce and Cheese Pizza"; bake()
dough = "Thin Crust Dough"; cut()
box()
sauce = "Marinara Sauce";
public ChicagoStyleCheesePizza() {
Defining its own style
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
33
9/22/11
NYStylePizzaStore ChicagoStylePizzaStore
createPizza() createPizza()
NYStylePepperoniPizza ChicagoStylePepperoniPizza
NYStyleClamPizza ChicagoStyleClamPizza
NYStyleVeggiePizza ChicagoStyleVeggiePizza
34
9/22/11
Challenge
Look
at
the
code
and
create
a
PortuguesePizzaStore
• factory.pizzafm
• Produces
pizzas
on
a
Portuguese
style…
• Make
Joaquim
order
some
portuguese
pizzas
(test
drive…)
35
9/22/11
CHICAGO
NEW YORK Calamari
FrozenClams
FreshClams
BruschettaSauce VeruThinCrust
ThickCrustDough
PlumTomatoSauce
MarinaraSauce ReggianoCheese
GoatCheese
MozarellaCheese
ThinCrustDough
CALIFORNIA
Next
steps:
1. Build
a
factory
for
each
region,
subclassing
from
PizzaIngredientFactory
and
implementing
all
create
methods
2. Implement
a
set
of
ingredients
classes
to
be
used
with
the
factory.
These
can
be
used
among
regions
where
appropriate.
3. Refactoring
PizzaStore
to
hook
up
these
factories.
36
9/22/11
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
String getName() {
return name;
}
37
9/22/11
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
} The prepare() method steps through creating a Here’s where the magic happens!
cheese pizza, and each time it needs a
ingredient, it asks the factory to produce it
} else if (item.equals("veggie")) {
} else if (item.equals("clam")) {
For each type of pizza, we instantiate
pizza = new ClamPizza(ingredientFactory); a new Pizza and give the factory it
pizza.setName("New York Style Clam Pizza"); needs to get its ingredients
} else if (item.equals("pepperoni")) {
}
return pizza;
}
}
38
9/22/11
39
9/22/11
prepare()
// other methods
<<interface>>
Dough
ThickCrustDough ThinCrustDough
<<interface>
PizzaIngredientFactory
createDough()
createSuace() <<interface>>
createCheese() Sauce
createVeggies()
createPepperoni()
createClam()
PlumTomatoSauce MarinaraSauce
NYPizzaIngredientFactory ChicagoPizzaIngredientFactory
<<interface>>
createDough() createDough() Cheese
createSuace() createSuace()
createCheese() createCheese()
createVeggies() createVeggies()
createPepperoni() createPepperoni()
createClam() createClam() MozzarellaCheese ReggianoCheese
<<interface>>
Clams
FrozenClams FreshClams
40
9/22/11
Challenge
The
Portuguese
style
pizza
usually
takes
• stuffed
dough
• cream
sauce
• fresh
cheese
• fresh
clams
• Artichoke
and
black
olives
41
9/22/11
Lazy
instantiation
• Important
for
resource
intensive
objects.
42
9/22/11
if (uniqueInstance == null) {
null
if (uniqueInstance == null) {
uniqueInstance =
new MySingleton(); <object1>
return uniqueInstance; <object1>
uniqueInstance = <object2>
new MySingleton();
<object2>
return uniqueInstance;
OOPSSS!!!
43
9/22/11
Improving
multithreading…
We
have
a
few
options
1. Do
nothing
if
the
performance
isn’t
critical
to
your
application.
2. Move
to
an
eagerly
created
instance
rather
than
a
lazily
created
one.
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
44
9/22/11
...and so on.
UNDO
Remote
Control
Vendor
classes
to
control
FaucetControl
CeilingLight ApplianceControl
TV openValue()
on() closeValue() on()
off() on() off()
Outdoor Light dim() off()
setInputChannel()
on() setVolume() Termostat
off() CeilingFan setTemperature() Stereo
high() GarageDoor on()
GardenLight medium() Hottub off()
up()
low() setCD()
down()
setDuskTime() off() circulate() setDVD()
stop()
setDawnTime() getSpeed() jetsOn() setRadio()
lightOn()
manualOn() jetsOff() setVolume()
lightOff()
manualOff() setTemperature()
Sprinkler
waterOn() SecurityControl Light
waterOff()
arm() on()
disarm() off()
45
9/22/11
Design
concerns
Separation
of
concerns.
• The
remote
should
know
how
to
interpret
button
presses
and
make
requests.
• The
remote
should
not
know
a
lot
about
house
automation.
-‐ How
to
turn
on
a
hot
tub,
how
to
dim
the
lights,
etc…
We
don’t
want
to
know
the
specifics
of
the
vendor
classes.
• IF
slot1
==
Light
THEN
light.on()
=
BAD
DESIGN!!!
• In
the
future
we
can
expect
more
vendor
classes
with
more
diverse
methods.
We
want
to
decouple
the
requester
of
an
action
from
the
object
that
actually
performs
the
action.
• “requester”
:
the
remote
control.
• “action
performer”
:
an
instance
of
one
of
the
vendor
classes.
46
9/22/11
orderUp()
RD
ER makeBurger(), makeFries()
O
ur
Yo seb output
hee s
lec h frie
ub
Do er wit ggies
urg d ve
The Order has all the instructions a n
3
Client
later asks to
execute command
action1()
action2()
setCommand() ...
Receiver
Invoker action1(), action2()
execute() execute()
Command
47
9/22/11
public SimpleRemoteControl() {}
Method for setting the command in
public void setCommand(Command command) { the slot. Could be called multiple
slot = command; times to change the behaviour of
the remote button
}
48
9/22/11
GarageDoor
remote.setCommand(garageOpen);
remote.buttonWasPressed();
}
}
49
9/22/11
LightOffCommand
OFF
LightOnCommand ON
LightOffCommand
LightOnCommand
CeilingFanOff
CeilingFanHigh
GarageDoorClose
GarageDoorOpen
StereoOff
StereoOnForCD
on()
off()
The Invoker
Stereo FEUP ● Nuno Flores ●
99
50
9/22/11
51
9/22/11
…
and
ConcreteCommand.
public class LightOnCommand implements Command {
Light light;
public RemoteControlWithUndo() {
onCommands = new Command[7];
offCommands = new Command[7];
52
9/22/11
53
9/22/11
Command[] commands;
54
9/22/11
Logging
requests
<<interface>> • Log
actions
to
be
able
to
recover
from
a
crash.
Command
execute() • As
we
execute
commands,
we
store
them
in
a
history
on
disk.
undo()
load() • When
a
crash
occurs,
we
reload
the
command
objects
and
invoke
store()
their
execute()
methods
in
batch
and
in
order.
• Ex:
database
processes,
large
data
handling,
communications,
etc…
55
9/22/11
Quick
Challenge
Implement
a
MacroCommand
that,
besides
setting
a
Party,
also
turns
on
the
house
outside
lights,the
garden’s
sprinkler
system
and
opens
the
living
room
windows.
Dont’
forget
“undo”.
Give
it
a
testing
try…
Check
the
rest
of
the
code,
just
for
the
record…
Adapter
concepts
• Unmatching
interfaces:
same
purpose,
different
publishing…
Your
Vendor
Existing
Class
System
Adapter New code
Your
Vendor
Existing No code changes
Class No code changes
Their interface doesn’t match the System
one you’ve written your code
against! This isn’t going to work!
56
9/22/11
and
a
turkey…
public interface Turkey {
public void gobble();
public void fly();
}
public class WildTurkey implements Turkey {
public void gobble() {
System.out.println("Gobble gobble");
}
57
9/22/11
l
expect er that cou of
e
togeth ise becaus erfaces.!
adaptee interface Adapter otherw patible int
incom
target interface
<<interface>> <<interface>>
Iterator Enumerator
hasNext() hasMoreElements()
next() nextElement()
remove()
Adaptee interface
Adaptee
EnumerationIterator <<interface>>
Enumerator
hasNext()
next() hasMoreElements()
Adapter remove() nextElement()
58
9/22/11
Challenge
Try
to
make
a
Chicken
look
like
a
Duck
Chicken
• It
cackles.
cackle()
• When
trying
to
fly,
it
flaps
and
falls.
flapWings()
fall()
Can
a
Duck
look
like
a
Chicken?
59
9/22/11
tuner
dvdPlayer
cdPlayer
Tuner
on()
amplifier DvdPlayer
off()
on() setCD()
off() setDVD() amplifier
setAM() setStereoSound()
on()
setFM() setSurroundSound()
off()
setFrequency() setTuner()
eject()
setVolume()
pause()
play()
Screen setSurroundAudio()
up() setTwoChannelAudio()
CdPlayer stop()
down()
amplifier
60
9/22/11
watchMovie()
endMovie()
listenToCD()
endCD()
listenToRadio()
endRadio()
Amplifier
tuner
dvdPlayer
cdPlayer
Tuner
on()
amplifier off()
DvdPlayer
setCD()
on()
setDVD() amplifier
off() setStereoSound()
setAM() setSurroundSound() on()
setFM() setTuner() off()
setFrequency()
setVolume() eject()
pause()
play()
Screen setSurroundAudio()
up() setTwoChannelAudio()
CdPlayer stop()
down()
amplifier
this.amp = amp;
this.tuner = tuner;
this.dvd = dvd;
this.cd = cd;
this.projector = projector;
this.screen = screen;
this.lights = lights;
this.popper = popper;
}
. . .
FEUP ● Nuno Flores ●
122
61
9/22/11
HomeTheaterFacade homeTheater =
new HomeTheaterFacade(amp, tuner, dvd, cd,
projector, screen, lights, popper);
62
9/22/11
Guidelines
• Given
any
object,
only
invoke
methods
that
belong
to:
-‐ The
object
itself
-‐ Objects
passed
in
as
a
parameter
to
the
method
-‐ Any
object
the
method
creates
or
instantiates
-‐ Any
components
of
the
object
(HAS-‐A
relationship)
public float getTemp() {
Without
the
principle
Thermometer t = station.getThermometer();
return t.getTemperature();
}
public float getTemp() { Like this we dont’ have to get
With
the
principle
station.getTemperature(); Thermometer object to get the
temperature.
}
63
9/22/11
public Car() {
// initialize engine, etc…
}
Here we’re creating a new object,
its methods are legal.
public void start(Key key) {
Doors doors = new Doors(); You can call a method on an object
passed as a parameter
64
9/22/11
Recipe
eparation
Coffee Pr
me water
(1)Boil so iling wate
r
) Br ew co ffee in bo
(2 p
ffee in cu
(3)Pour co
lk
gar and mi
(4)Add su
pe
ation Reci
Tea Prepar
me wate r
(1)Boil so ing water
ep te a in boil
(2)Ste
a in cup
(3)Pour te
mon
(4)Add le
65
9/22/11
void prepareRecipe() {
boilWater();
brewCoffeeGrinds();
pourInCup();
addSugarAndMilk();
}
Here is the recipe for making the drink.
public void boilWater() { Each of the steps is implemented as a
System.out.println("Boiling water"); separate method.
}
prepareRecipe() prepareRecipe()
brewCoffeeGrinds() steepTeaBag()
addSugarAndMilk() addLemon()
66
9/22/11
Abstracting
prepareRecipe()
Coffee Tea
void prepareRecipe() { void prepareRecipe() {
boilWater(); boilWater();
brewCoffeeGrinds(); brewCoffeeGrinds();
pourInCup(); pourInCup();
addSugarAndMilk(); addSugarAndMilk();
} }
void prepareRecipe() {
boilWater();
brew();
pourInCup(); {
public abstract class CaffeineBeverage
addCondiments();
It is declared final so that the }
subclasses can’t override it.
final void prepareRecipe() {
boilWater(); Now the same prepareRecipe()
brew(); method will be used to make
pourInCup(); both Tea and Coffee.
addCondiments();
}
Because Coffee and Tea handle these
abstract void brew(); methods in differrent ways, they’re going
to have to be declared as abstract. Let
the subclasses worry about that stuff!
abstract void addCondiments();
void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
} FEUP ● Nuno Flores ●
133
The
only
method
they
need
to
implement
are
the
abstract
brew()
and
addCondiments()
67
9/22/11
… and some methods are pourInCup(); In the template, each step of the
handled by the subclass. algorithm is represented by a
addCondiments(); method.
void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
}
68
9/22/11
void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
void boilWater() {
System.out.println("Boiling water");
} Technically,
these are also
hooks, but ther is
void pourInCup() { no point in
System.out.println("Pouring into cup"); overriding them.
}
Subclasses may (or not)
boolean customerWantsCondiments() { override this one.
return true; They should whereas its
} default implementation is
} nearly empty
FEUP ● Nuno Flores ●
137
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
}
69
9/22/11
High-Level
Component
The high-level components
control the when and how
Low-Level Low-Level
Component Component
A low-level component
Low-level components can Low-Level never calls a high-level
participate in the Component component directly
computation
70
9/22/11
this.setSize(300,300);
this.setVisible(true);
JFrame’s update algorithm calls
} paint(). By default paint() does
nothing...it’s a hook.
public void paint(Graphics graphics) {
super.paint(graphics);
String msg = "I rule!!";
graphics.drawString(msg, 100, 100);
} We’re overriding paint() and telling
the JFrame to draw a message in
the window
public static void main(String[] args) {
MyFrame myFrame = new MyFrame("Head First Design
Patterns");
}
}
FEUP ● Nuno Flores ●
142
71
9/22/11
Challenge
Create
a
class
called
MakeEggs
that
allows
sub-‐classes
to
customize
the
way
they
bake
eggs.
• Of
course,
there
is
always
a
ordered
procedure
to
make
eggs…
• And
some
things
can’t
change…
72
9/22/11
public PancakeHouseMenu() {
menuItems = new ArrayList();
73
9/22/11
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("Vegetarian BLT",
"(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99);
// add other items here...
}
The
problem?
Java-‐Enabled
“Waitress”
specification
• printMenu()
-‐ prints
every
item
on
the
menu
• printBreakfastMenu()
...
-‐ prints
just
breakfast
items
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
ArrayList breakfastItems = pancakeHouseMenu.getMenuItems();
• printLunchMenu()
-‐ prints
just
lunch
items
DinerMenu dinerMenu = new DinerMenu();
MenuItems[] lunchItems = dinerMenu.getMenuItems();
• printVegetarianMenu()
...
-‐ prints
all
vegetarian
menu
items
• isItemVegetarian(name)
-‐ given
the
name
of
an
item,
returns
true
it
the
item
is
vegetarian,
otherwise
returns
false.
Now, we have to implement two
different loops to step through the
two implementations of the menu
for (int i = 0 ; i < breakfastItems.size(); i++) { items...
MenuItem menuItem = (MenuItem) breakfastItems.get(i);
System.out.print(menuItem.getName() + “ “);
System.out.print(menuItem.getPrice() + “ “);
System.out.print(menuItem.getDescription()); ...one loop the the ArrayList...
}
74
9/22/11
Array
3
MenuItem MenuItem MenuItem MenuItem
MenuItem
0 1 2 3
ArrayList Iterator iterator = lunchMenu.createIterator();
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem)iterator.next();
} Array
Iterator iterator = breakfastMenu.createIterator();
next()
while (iterator.hasNext()) { 0
MenuItem menuItem = (MenuItem)iterator.next(); lunchItems[0] MenuItem
} Iterator
next() lunchItems[1]
1
MenuItem
Iterator lunchItems[2]
get(3)
get(2) 2
get(1)
get(0)
MenuItem
lunchItems[3]
3
MenuItem MenuItem MenuItem MenuItem MenuItem
0 1 2 3 FEUP ● Nuno Flores ●
ArrayList 149
DinerMenuIterator DinerMenuIterator is an
implementation of Iterator
hasNext() that knows how to iterate
next()
over an array of MenuItems.
FEUP ● Nuno Flores ●
150
75
9/22/11
// addItem here...
76
9/22/11
System.out.println("MENU\n----\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH"); And then calls the overloaded
printMenu(dinerIterator); printMenu() with each iterator
}
test if there are any
private void printMenu(Iterator iterator) { more items
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem)iterator.next(); get the next item
System.out.print(menuItem.getName() + ", ");
System.out.print(menuItem.getPrice() + " -- ");
System.out.println(menuItem.getDescription());
}
The overloaded printMenu()
} method uses the Iterator to
step through the menu items
// other methods here... Note: we’re down and print them.
} to one loop.
PancakeHouseMenu <<interface>>
Waitress Iterator
menuItems
printMenu() hasNext()
next()
createIterator()
DinerMenu
Encapsulated iteration:
implementation lives outside
the aggregate with only a few
methods to allow traversal.
77
9/22/11
Menu pancakeHouseMenu;
Menu dinerMenu;
<<interface>> <<interface>>
Waitress Iterator
Menu
Hum, this resembles the
createIterator() printMenu() hasNext()
FACTORY METHOD
next()
pattern...is it??
78
9/22/11
79
9/22/11
public CafeMenu() {
addItem("Veggie Burger and Air Fries",
"Veggie burger on a whole wheat bun, lettuce, tomato, and fries",
true, 3.99);
addItem("Soup of the day",
"A cup of the soup of the day, with a side salad",
false, 3.69);
addItem("Burrito",
"A large burrito, with whole pinto beans, salsa, guacamole",
true, 4.29);
}
Key MenuItem
1
MenuItem
Key MenuItem
Dessert Menu
2
MenuItem
0 Key MenuItem
MenuItem 3
MenuItem
1
Hashtable
MenuItem
3
MenuItem
80
9/22/11
We
must
refactor
our
code
in
order
for
it
to
grow
• Otherwise,
would
leave
us
a
rigid,
inflexible
code,
unprone
to
change.
That
is…
We need to accommodate
Menus... All Menus
We need to be able
to traverse all items … and menu items.
in the tree.
MenuItem MenuItem MenuItem MenuItem
81
9/22/11
A Leaf has no
children.
Client
MenuComponent
Waitress getName()
getDescription()
getPrice()
isVegetarian()
print()
Methods for manipulating add(MenuComponent)
the components remove(MenuComponent)
getChild(int)
Leaf
Composite
MenuItem Menu
getName() menuComponents
getDescription()
getPrice() getName()
isVegetarian() getDescription()
print() print()
add(MenuComponent)
remove(MenuComponent)
getChild(int)
82
9/22/11
83
9/22/11
public Menu(String name, String description) { Now Menu has a name and a
this.name = name; description. Earlier we had a
this.description = description; different class for each menu.
}
...
84
9/22/11
85
9/22/11
Challenge
A
company
wants
to
build
a
tree-‐like
system
for
storing
data
about
its
departments
and
employees.
There
are
Tecnicians,
Laborers
and
Supervisors.
The
supervisors
may
supervise
other
Employees
including
other
supervisores.
One
functionality
includes
printing
the
names
of
the
employees
supervised
by
a
certain
supervisor.
Solve
their
problem…
86
9/22/11
Gumball
Machine
State
machine
turns crank
Has Quarter
inserts quarter
Gumball Sold
No Quarter
A
straightforward
implementation…
public class GumballMachine {
87
9/22/11
Repercussions??
final static int SOLD_OUT = 0;
final static int NO_QUARTER = 1; First, you’d have to add a new WINNER
final static int HAS_QUARTER = 2; state here. That isn’t too bad...
final static int SOLD = 3;
...
FEUP ● Nuno Flores ●
175
3. Dump all conditional code and delegate the work to the state class
88
9/22/11
State soldOutState;
State noQuarterState;
State hasQuarterState; States are now classes,
State soldState; instead of integer constants.
void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if (count != 0) {
count = count - 1; There are still a few methods
} missing: getters for each State and
} getCount() FEUP ● Nuno Flores ●
178
89
9/22/11
GumballMachine gumballMachine;
90
9/22/11
Strategy
• Flexible
alternative
to
subclassing.
• Change
behaviour
by
composition
instead
of
inheritance.
91
9/22/11
inserts quarter
Gumball Sold
No Quarter
92
9/22/11
Proxy
Gumball Gumball
Monitor Machine
Local Heap Remote Heap
Same as old code, only it The Remote object IS the
thinks its talking to the real Real Thing. It’s the object with
object, but actually its a proxy the method that actually does
the real work.l
FEUP ● Nuno Flores ●
186
93
9/22/11
Proxy
94
9/22/11
ImageIcon ImageProxy
subject
getIconWidth() getIconWidth()
getIconHeight() getIconHeight()
paintIcon() paintIcon()
1. ImageProxy
first
creates
an
ImageIcon
and
starts
loading
if
from
a
network
URL.
2. While
the
bytes
of
the
image
are
being
retrieved,
ImageProxy
displays
a
status
message
“loading”
3. When
the
Image
is
fully
loaded
ImageProxy,
delegates
all
method
calls
to
image
icon
(all
methods
seen
above)
4. If
the
user
request
a
new
image,
we’ll
create
a
new
proxy
and
start
the
process
again.
FEUP ● Nuno Flores ●
190
95
9/22/11
...
if (!retrieving) {
retrieving = true;
retrievalThread = We don’t want to hang up the
If we aren’t already new Thread(new Runnable() { entire user interface so we use
another thread to retrieve the
trying to retrieve the public void run() { image.
image...
try {
...then start retrieving it. imageIcon = new ImageIcon(imageURL, "CD Cover");
Don’t worry, only one c.repaint();
thread calls paint. We instantiate the Icon object, but
} catch (Exception e) { the constructor won’t return until
the image is loaded.
e.printStackTrace(); When we have the image ,
} we tell Swing that we need
to be repainted.
}
});
retrievalThread.start();
}
}
}
}
96
9/22/11
<<interface>> <<interface>>
Subject InvocationHandler
request() invoke()
Proxy
RealSubject
InvocationHandler
request()
request()
invoke()
A
Person
public String getGender() {
return gender;
}
97
9/22/11
dynamic proxies
Proxy OwnerInvocationHandler
appropriate
proxy
Proxy NonOwnerInvocationHandler
request() invoke()
98
9/22/11
99
9/22/11
Challenge
Add
a
container
to
PersonBean
where
you
can
add
testemonials
by
friends.
Make
a
new
Proxy
for
friends
of
the
person,
that
only
allows
adding
testemonials.
100
9/22/11
View Controller
The model notifies the
view of a change in
state
my state has changed!
update yourself! “player.play()
controller manipulates
The model contains all the state, data, the model
and application logic needed to Model
amaintain and play mp3s.
101
9/22/11
A
closer-‐look
Here’s the creamy
controller; it lives in
the middle
1 2
The user did something Change your state
Controller
3
Change your display
4
I’ve changed
View 5 Model
I need your state information Here’s the model; it
This is the user
handles all application
interface
data and logic
COMPOSITE OBSERVER
I’ve changed
View Model
I need your state information
102
9/22/11
OBSERVER
Observers
My state has
Observable changed!
View
View
Model
STRATEGY
The user did The controller is the strategy
something for the view - it’s the object
that knows how to handle
user actions.
103
9/22/11
COMPOSITE paint()
Form Title
Enter Text
OK
View
Final
Quiz
30
minutes…GO!
104
9/22/11
Final
Challenge
Pretende-‐se
desenhar
uma
aplicação
de
GPS.
• O
GPS
deve
apresentar
um
conjuntos
de
elementos
gráficos
que
representem
os
elementos
reais,
e
que
se
compõem
uns
com
os
outros.
• Deves
actualizar
periodicamente
o
seu
display
há
medida
que
o
tempo
passa
com
dados
do
satélite.
• Deve
poder
comunicar
com
outros
dispositivos
para,
sendo
que
estes
devem
apenas
aceder
ao
determinada
informação
do
GPS
• Ao
ligar,
o
dispositivo
GPS
deve
verificar
se
existem
satélites,
se
existem
3
ou
mais
começa
a
actualizar-‐se,
se
existem
2
ou
menos
tenta
ligar-‐se
a
outros
dispositivos
GPS
próximos
a
tentar
captar
mais
informação
relevante,
se
não
houver
satelite
nenhum,
desliga-‐se.
Quando
está
desligado,
mantém
sempre
uma
luz
de
presença.
• Deve
ser
possível
mostrar
a
informação
segundo
várias
vistas
diferentes
(texto,
2D,
3D).
• Deve
conseguir
interagir
com
a
API
de
dispositivos
similares
de
outros
fabricantes.
FEUP ● Nuno Flores ●
209
So…
• Problem:
How
do
I
get
to
work
in
time?
• Context:
I’ve
locked
my
keys
in
my
car.
• Solution:
Break
the
window,
get
in
the
car,
start
the
engine
and
drive
to
work.
(time
and
distance
constraints
resolved!)
• Is
this
a
pattern?
-‐ Missing
“recurring”
-‐ Missing
constraint
“cost”
-‐ It
is
not
a
GOOD,
EXPERIENCED
and
COST-‐EFFECTIVE
solution.
-‐ Its
missing
a
NAME!
105
9/22/11
Intent
• What
the
pattern
does
in
a
short
statement
(the
post-‐its!!!)
• Pattern
definition,
its
“abstract”.
Motivation
• Concrete
scenario
that
describes
the
problem
and
how
the
solution
solves
the
problem.
FEUP ● Nuno Flores ●
211
Structure
• Provides
a
diagram
illustrating
the
relationships
among
classes
that
participate
in
the
pattern
(as
the
ones
in
the
design
billboard).
Participants
• Describes
the
responsibilities
and
roles
of
the
classes
and
objects
in
the
design.
Collaborations
• How
the
participants
work
together
in
the
pattern.
Consequences
• Effects
that
using
this
patterns
may
have:
good
and
bad.
FEUP ● Nuno Flores ●
212
106
9/22/11
Knows
Uses
• Describes
examples
of
this
pattern
found
in
real
systems.
Related
Patterns
• Describes
the
relationship
between
this
pattern
and
the
others.
www.fe.up.pt/~aaguiar/as/gof
Get
your
ideias
down
on
a
paper
in
a
way
other
can
understand.
• Must
be
easy
to
read
and
understand.
Provides
feedback
to
your
design.
• Use
the
template
of
catalogs.
It
has
to
make
sense
for
others.
107
9/22/11
108
9/22/11
Anti-‐Patterns
An
AntiPattern
is
a
pattern
that
tells
how
to
go
from
a
problem
to
a
bad
solution.
• Identifying
bad
practices
can
be
as
valuable
as
identifying
good
practices.
• Tells
you
why
the
bad
solution
looks
attractive.
• Why
it
turns
out
to
be
bad.
• What
positive
patterns
are
applicable
in
its
stead.
“CopyAndPasteProgramming”
Problem:
Reusing
code
with
a
minimum
of
effort.
Context:
Trying
to
optimize
reuse
when
maintaining
an
existing
system.
Forces:
Design-‐time
reuse
is
a
lot
of
work.
If
a
system
has
already
been
implemented,
the
reusable
assets
are
there
for
the
picking.
During
maintenance,
you
often
do
not
know
the
assumptions
that
a
module
is
making,
so
changing
it
is
risky.
It
is
safer
to
add
new
code
than
to
change
old
code.
Restructuring
existing
code
to
be
more
reusable
(called
ReFactoring
by
Opdyke
et
al.
[1])
is
expensive,
particularly
if
the
system
is
large.
Supposed
Solution:
Minimize
reuse
costs
by
cloning
code
and
modifying
it
to
suit
new
contexts.
Resulting
Context:
Reuse
is
easy,
though
specific
blocks
of
reusable
code
are
duplicated
across
the
source
spectrum.
Individual
bug
fixes
or
enhancements
to
the
original
source
must
be
individually
ported
to
all
clones
if
and
when
they
can
be
tracked
down.
Design
Rationale:
Short-‐term
pay-‐off
is
more
easily
justified
than
a
boondoggle
that
promises
long-‐term
investment
without
any
conclusive
proof.
Appropriate
Usage:
If
the
copies
of
the
code
will
be
heavily
modified,
it
can
be
better
to
have
the
separate
copies
so
that
each
can
be
changed
independently.
Later
CodeHarvesting
eliminates
redundancy
after
the
finer
points
have
been
worked
out.
It
can
also
be
handy
to
have
two
variants
of
a
piece
of
code
when
debugging
one
variant
only,
setting
breakpoints
in
the
variant
of
interest.
Synonyms:
CloneAndModifyProgramming,
SnarfAndBarfProgramming,
ClipboardInheritance?,
ClipboardCoding?,
RapeAndPasteProgramming
109
9/22/11
Intermediate
Mind
• As
the
learning
progresses,
the
Intermediate
mind
starts
to
see
where
patterns
are
needed
and
where
they
aren’t
• “Maybe
I
need
a
Singleton
here”
Zen
Mind
• The
Zen
Mind
is
able
to
see
patterns
where
they
fit
naturally.
• “This
is
a
natural
place
for
Decorator”
110
9/22/11
Websites
• Portland
Patterns
Repository
-‐ http://c2.com
• Hillside
Group
-‐ http://hillside.net
Leftover
patterns
BRIDGE
• Decouple
an
abstraction
from
its
implementation
so
that
the
two
can
vary
independently.
BUILDER
• Separates
the
construction
of
a
complex
object
from
its
representation
so
that
the
same
construction
process
can
create
different
representations
FLYWEIGHT
• Use
sharing
to
support
large
numbers
of
fine-‐grained
objects
efficiently.
INTERPRETER
• Given
a
language,
define
a
representation
for
its
grammar
along
with
an
interpreter
that
uses
the
representation
to
interpret
sentences
in
the
language.
111
9/22/11
Leftover
patterns
MEDIATOR
• Define
an
object
that
encapsulates
how
a
set
of
objects
interact.
Promotes
loose
coupling
by
keeping
objects
from
referring
to
each
other
explicitly,
and
its
lets
yo
vary
their
interaction
dependently.
MEMENTO
• Without
violating
encapsulation,
capture
and
externalize
an
object’s
internal
state
so
that
the
object
can
be
restored
to
this
stage
later.
PROTOTYPE
• Specify
the
kinds
of
objects
to
create
using
a
prototypical
instance,
and
create
new
objects
by
copying
this
prototype.
VISITOR
• Represent
an
operation
to
be
performed
on
the
elements
of
an
object
structure.
Lets
you
define
a
new
operation
without
changing
the
classes
of
the
elements
on
which
it
operates.
112