0% found this document useful (0 votes)
9 views254 pages

1 Strategy Merged

Uploaded by

leanhtuan280704
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views254 pages

1 Strategy Merged

Uploaded by

leanhtuan280704
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 254

ThS.

Trần Thị Thanh Nga


Khoa CNTT, Trường ĐH Nông Lâm TPHCM
Email: [email protected]

1
The Specifications
 Joe works at a company
that produces a simulation
game called SimUDuck. He
is an OO Programmer and
his duty is to implement
the necessary functionality
for the game

 The game should have the following specifications:


 A variety of different ducks should be integrated into the
game
 The ducks should swim
 The ducks should quake

2
A First Design for the Duck Simulator Game

Duck All ducks quack() and swim(). The


superclass takes care of the implementation
quack()
swim()
display() The display() method is abstract since
//other duck like methods all the duck subtypes look different

Each duck subtype is responsible for


MallardDuck RedHeadDuck implementing its own display()
behavior for how it looks on the screen
display() display()
Lots of other types of ducks
inherit from the Duck type

3
But now we need the ducks to fly…
Joe, at the shareholders meeting
we decided that we need to
crush the competition. From
now on our ducks need to fly.

Duck

quack()
swim()
display()
fly() All subclasses inherit fly()

MallardDuck RedHeadDuck

display() display()
4
But something went horribly wrong...
 At a demo the program failed to impress anyone -- there
were rubber ducks flying across the screen!

What happened? Duck


A localized update to the
code caused a non-local side quack()
effect (flying rubber ducks) swim() By putting fly() in the
display() superclass Joe gave flying
fly() ability to all ducks including
those that shouldn’t

MallardDuck RedHeadDuck RubberDuck

display() display() quack()


display()
5
Inheritance at Work public class Duck {
Duck
...
public void fly() {
+quack ()
// fly implementation
+swim ()
+display() }
+fly() public void quack() {
System.out.println("quack, quack");
}
}

MallardDuck RedHeadDuck RubberDuck We can override the fly() method in the


rubber duck in a similar way that we
+display() +dsplay () + quack() override the quack() method
+ fly()
+ display() public class RubberDuck extends Duck {
...
quack quack squick public void fly() { }
public void quack() {
System.out.println(
"squick, squick");
}
}
6
Yet Another Duck is Added to the Application
 What would happen if we added a
Duck
DecoyDuck to the class hierarchy?
+quack () It doesn’t quack() or fly().
+swim ()
+display ()
+fly()
public class DecoyDuck
extends Duck {
...
MallardDuck RedHeadDuck RubberDuck DecoyDuck public void fly() {
// do nothing
+display () +display () + quack() + quack() }
+ fly() + fly() public void quack() {
+ display () + display ()
// do nothing
}
}

7
How about an interface?
 Need a cleaner way to make some ducks fly or quack.
 Could take the fly() out of the superclass and make an Flyable
interface with a fly() method. Each duck that is supposed to fly
will implement that interface
 and maybe a Quackable interface as well.

<<Interface>> <<Interface>> Duck


Flyable Quackable
+ swim()
+ fly() + quack() + display()
// other duck like methods
What do you
think about
this design?

MallardDuck RedHeadDuck RubberDuck DecoyDuck

+ fly() + fly() + quack() + display()


+ quack() + quack() + display()
+ display() + display()
8
What do you think?
 Dumb!!!!

 “Duplicate code” all over the place.


 Interface not reuse code
 A small change to the flying behavior will require
changing all 48 of the Duck subclasses!

9
Embracing Change
 In SOFTWARE projects you can count on one thing
that is constant:

CHANGE
 Solution
 Deal with it.
 Make CHANGE part of your design.
 Identify what vary and separate from the rest.

Let’s shoot some ducks!

10
Change is a taste of life

11
Design Principle

Encapsulate
what varies

12
The Constitution of Software Architects
 Encapsulate what varies.
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????

13
Embracing Change in Ducks
 fly() and quack() are the parts that vary
 We create a new set of classes to represent each behavior

<<Interface>> <<Interface>>
FlyBehavior QuackBehavior

+ fly() + quack()

FlyWithWings FlyNoWay Quack Squick MuteQuack

+ fly() + fly() + quack() + quack() + quack()

print("I'm flying!") print("Quack") print("...")

print("I can't fly.") print("Squeak")


14
Design Principle

Program to an interface
not to an implementation

15
The Constitution of Software Architects
 Encapsulate what varies.
 Program through an interface
not to an implementation
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????

16
Design Principle Example
Animal

+ makeSound() Program through an implementation


Dog dog = new Dog();
dog.bark();

Dog Cat
+ makeSound() { + makeSound() { Program through an interface
bark(); meow();
} Animal dog = new Dog();
}
+ bark() dog.makeSound();
+ moew()

17
Integrating the Duck Behavior
The behavior variables Instance variables hold a
Duck
are declared as the reference to a specific
- flyBehavior : FlyBehavior
behavior interface type. behavior at runtime.
- quackBehavior : QuackBehavior

These replace the + performQuack() quackBehavior.quack();


+ performFly()
fly() and quack() + swim() flyBehavior.fly();
methods. + display()

MallardDuck RedHeadDuck RubberDuck DecoyDuck

+ display() + display() + display() + display()

class MallardDuck extends Duck { class DecoyDuck extends Duck {


public MallardDuck() { public DecoyDuck() {
flyBehavior = new FlyWithWings(); flyBehavior = new FlyNoway();
quackBehavior = new Quack(); quackBehavior = new MuteQuack();
} }
} }
18
Design Principle Ahead
Duck Each Duck HAS A FlyingBehavior and
- flyBehavior : FlyBehavior a QuackBehavior to which it delegates
- quackBehavior : QuackBehavior flying and quacking behaviors

+ performQuack()
+ performFly() Composition
+ swim()
+ display()
Instead of inheriting behavior, the duck
get their behavior by being composed
with the right behavior object

19
Design Principle

Favor Composition over


Inheritance

20
The Constitution of Software Architects
 Encapsulate what varies.
 Program through an interface
not to an implementation
 Favor Composition over
Inheritance
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????

21
Putting it together…
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings();
}
} public class Quack implements QuackBehavior {
public void quack() {
System.out.println("Quack");
}
} public class FlyWithWings implements FlyBehavior {
public void fly() {
System.out.println("I'm flying!!");
}
}

public class MiniDuckSimulator {


public static void main(String[] args) {
Duck mallard = new MallardDuck();
mallard.performQuack(); I'm a real Mallard duck
mallard.performFly(); Quack
}
I'm flying!!
}
22
Setting Behavior Dynamically!
Duck
- flyBehavior : FlyBehavior public void setFlyBehavior(FlyBehavior fb) {
- quackBehavior : QuackBehavior flyBehavior = fb;
}
+ performFly() public void setQuackBehavior(QuackBehavior qb) {
+ performQuack() quackBehavior = qb;
+ swim() }
+ display()
+ setFlyBehavior(f : FlyBehavior)
+ setQuackBehavior(q : QuackBehavior)

// Create a new type of Duck // Test it out in main


public class ModelDuck extends Duck { ModelDuck model = new ModelDuck();
public ModelDuck() { model.performFly();
flyBehavior = new FlyNoWay(); model.setFlyBehavior(
quackBehavior = new Quack(); new FlyRocketPowered());
} model.performFly();
public void display() {
System.out.println("I'm a model duck");
}
} // Make a new FlyBehavior type
public class FlyRocketPowered implements FlyBehavior {
public void fly() {
System.out.println("I'm flying with a rocket");
}
} 23
The Big Picture <<Interface>>
FlyBehavior
Duck
- flyBehavior : FlyBehavior + fly()
- quackBehavior : QuackBehavior

+ performFly()
+ performQuack()
+ swim() FlyWithWings FlyNoWay FlyRocketPower
+ display() + fly() + fly() + fly()
+ setFlyBehavior(f : FlyBehavior)
+ setQuackBehavior(q : QuackBehavior)
<<Interface>>
QuackBehavior

MallardDuck RedHeadDuck RubberDuck DecoyDuck

+ display() + display() + display() + display()


Quack Squick MuteQuack

+ quack() + quack() + quack()

24
Behavior Reuse

25
The Strategy Design Pattern
The Strategy Design Pattern defines a family of algorithms,
encapsulates each one, and makes them interchangeable. Strategy
lets the algorithms vary independently from the clients that use it.

Context manages the data structures


that a concrete strategy operates on.
Defines the generic interface
Context
- strategy : Strategy <<Interface>>
Strategy
+ Context(s : Strategy)
+ setStrategy(s : Strategy) + runAlgorithm()
+ runAlgorithm()

strategy.runAlgorithm(); ConcreteStrategyA ConcreteStrategyB ConcreteStrategyC

+ runAlgorithm() + runAlgorithm() + runAlgorithm()


ConcreteStrategy classes provide the implementations of the different strategies. These
operate on the data structures in the the Context, and can be set dynamically.
26
Summary
 Strategy pattern allows selection of one of several
algorithms dynamically.
 Algorithms may be related via an inheritance hierarchy
or unrelated [must implement the same interface]
 Strategies don’t hide everything -- client code is
typically aware that there are a number of strategies
and has some criteria to choose among them -- shifts
the algorithm decision to the client.

27
Keeping your Objects in the Know!

1
Observer – A Non Software
Example

2
Motivation Weather Station
 Build a weather monitoring station that have
 Weather Station – hardware device which collects data from various
sensors (humidity, temperature, pressure)
 WeatherData object which interfaces with the Weather Station
hardware
 Need to implement three display elements that use the
WeatherData and must be updated each time WeatherData
has new measurements
 a current conditions display Temp, Humidity, Pressure change
 a weather statistics display Avg. temp, Min. temp, Max. temp
 and a forecast display
 The system must be expandable
 can create new custom display elements and can add or remove as
many display elements as they want to the application.

3
A Weather Monitoring Application
What we have What we need to
implement
Temperature sensor
device
Weather forecast

Presure sensor
device Current conditions
Weather data
Weather object
station

Humidity sensor Weather statistics


device
4
The WeatherData class
WeatherData These three methods return the most recent
weather measurements for temperature,
humidity, and pressure respectively.
+ getTemperature()
+ getHumidity() We don’t care HOW these variables are set; the
+ getPressure() WeatherData object knows how to get updated
+ measurementChanged() information from the Weather Station
// other methods

This method is called anytime


new weather measurement
data is available

5
A First Misguided Attempt at the
Weather Station
public class WeatherData {
// instance variable declarations
public void measurementsChanged() {
float temp = getTemperature(); Grab the most recent
measurements by calling the
float humidity = getHumidity();
WeatherData’s getter methods
float pressure = getPressure(); (already implemented)

currentConditionsDisplay.update(
temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
} Now update the displays.
Call each display element to update
// other WeatherData methods here its display, passing it the most
recent measurements.
}

6
What’s wrong with the first
implementation?
public class WeatherData {
// instance variable declarations
public void measurementsChanged() {
float temp = getTemperature();
float humidity = getHumidity();
Area of change, we need
float pressure = getPressure(); to encapsulate this.

currentConditionsDisplay.update(temp, humidity, pressure);


statisticsDisplay.update(temp, humidity, pressure);
forecastDisplay.update(temp, humidity, pressure);
}
// other WeatherData methods here
}
At least we seem to be using a common
interface to talk to the display elements…
By coding to concrete implementations they all have an update() method that
we have no way to add or remove other takes temp, humidity and pressure values.
display elements without making
changes to the program.
7
Publisher + Subscriber = Observer
When data in the WeatherData object The displays have
changes, the observers are notified subscribed with the
WeatherData to receive
updates when when the
Weather data changes
Weather forecast

Weather data
object

New data values are


communicated to the observers
in some form when they change Current conditions

This object isn’t an


observer so it doesn’t get Observer
notified when the objects
subject data changes Weather statistics

8
Adding Observers
 A TV station comes along and tells the Weather data
that it wants to become an observer

register/
subscribe me

9
Adding Observers
 The TV station is now an official observer
 It gets a notification when the Weather object has changed

10
Removing Observers
 One of the displays asks to be removed as an observer

Remove
Unsubscribe
me

11
Removing Observers
 All the other observers can get another notification
except the the display that has been recently removed
from the set of observers

12
Design Principle
Strive for loosely coupled designs
between objects that interact.

 Loosely coupled designs allow us to build flexible OO


systems that can handle changes because they
minimize the interdependency between objects.

13
The Constitution of Software Architects
 Encapsulate what varies
 Program through an interface not to an implementation
 Favor Composition over Inheritance
 Classes should be open for extension but closed for
modification
 Strive for loosely coupled designs between objects that
interact.
 ?????????
 ?????????
 ?????????
 ?????????

14
The Observer Pattern
 Define a one-to-many dependency between objects so that
when one object changes state, all its dependents are
notified and updated automatically.

Motivation for
Observer Pattern

15
Structure Observer Pattern
Knows its numerous observers. Provides an interface for
attaching and detaching observer objects. Defines an Update interface
Sends a notification to its observers when its state changes. for concrete observers, that
gets called when the
Subject’s state changes.

Concrete observers can be


any class that implements
the Observer interface.
Each observer registers
with a concrete subject to
receive updates.

A concrete subject always implements the Subject interface.


In addition to the register (attach) and remove (detach)
methods, the concrete subject implements a notify() method
to notify observers whenever state changes.
16
Consequences
 Abstract coupling between subject and observer
 Coupling is abstract, thus minimal (concrete class isn’t
known).
 Can have multiple layers of abstraction.
 Support for broadcast communication
 Subject doesn’t need to know its receivers.
 Unexpected updates
 Can be blind to some changes in the subject (i.e.,
observer doesn’t know “what” has changed in the
subject).

17
Designing the Weather Station
<<Interface>>
Subject <<Interface>> <<Interface>>
0..* Observer DisplayElement
+ registerObserver()
+ unregisterObserver() + update() + display()
+ notifyObservers()
All weather
components
Subject interface implement the
Observer interface.
ForecastDisplay
WeatherData + update()
+ display()
+ getTemperature() : double
+ getHumidity() : double
+ getPressure() : double
+ measurementChanged() CurrentConditionDisplay StatisticDisplay
+ registerObserver(o : Observer)
+ unregisterObserver(o : Observer) + update() + update()
+ notifyObservers() + display() + display()
WeatherData now
implements the
Subject interface.
18
Implementing the Weather Station
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}

public interface Observer {


public void update(float temp, float humidity,
float pressure);
}

public interface DisplayElement { These are the state values the


public void display(); Observers get from the Subject when
} a weather measurement changes.

19
Implementing the Subject Interface
public class WeatherData implements Subject {
private ArrayList observers;
private float temperature; Added an ArrayList to hold
private float humidity;
private float pressure; the Observers, and we create
public WeatherData() { it in the constructor
observers = new ArrayList();
}
public void registerObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) { Here we implement
int j = observers.indexOf(o); the Subject
if (j >= 0) { observers.remove(j); } Interface
}
public void notifyObservers() {
for (int j = 0; j < observers.size(); j++) {
Observer observer = (Observer) observers.get(j);
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged() {
notifyObservers(); Notify the observers when
} measurements change.
}
20
The Display Elements The constructors passed the
weatherData object (the subject)
and we use it to register the
public class CurrentConditionsDisplay display as an observer.
implements Observer, DisplayElement {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temperature, float humidity,
float pressure) {
this.temperature = temperature; When update ( ) is called,
this.humidity = humidity; we save the temp and
display(); humidity and call display ( )
}
public void display() {
System.out.println("Current conditions : "
+ temperature + "F degrees and "
+ humidity + "% humidity");
}
}
21
Java’s Built-in Observer Pattern
 For an Object to become an Observer:
 Implement the java.util.Observer interface and call
addObserver() on any Observable object. To remove use
deleteObserver() method.
 For the Observable to send notifications
 Extend java.util.Observable superclass
 Then a 2 step process:
1. First call the setChanged() method to signify that the state has
changed in your object.
2. call one of two methods: notifyObservers() or
notifyObservers(Object arg)
 For the Observer to receive notifications
 Implement the update() method as before
update(Observable o, Object arg)

22
Java’s Built-in Observer Pattern
 Observer == Observer
 Observable == Subject

WeatherData does not


need to implement
register, remove and
notify -- it inherits them
23
Rework the CurrentConditionsDisplay
import java.util.Observable;
import java.util.Observer; implement java.utils.Observer
public class CurrentConditionsDisplay
implements Observer, DisplayElement {
Observable observable;
private float temperature;
private float humidity;

public CurrentConditionsDisplay(Observable observable) {


this.observable = observable;
observable.addObserver(this);
}

public void update(Observable obs, Object arg) {


if (obs instanceof WeatherData) {
WeatherData weatherData = (WeatherData)obs;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}
24
Implementation Issues: Updates
 The simple observer protocol does not specify what
changed in the subject
 More fine-grained update protocols may specify the
extent of the change:
 update(Object changedState)
or cellUpdate (int x, int y, float value)
 Some observers may observe more than one subject
(many-to-many relation) E.g., a graph can depend on
several different sheets
 The update should specify which subject changed:
update(Subject changedSubject)

25
Update Protocols: Push or Pull
 Pull: The subject should provide an interface that enables
observers to query the subject for the required state
information to update their state.
 Push: The subject should send the state information that
the observers may be interested in.
 Pull assumes no knowledge of the subject about its
observers, so it is more re-usable but less efficient.
 Push assumes that the subjects has some knowledge about
what the observers need, so it is less re-usable but more
efficient.
 Intermediate: when the observer registers using attach(), it
specifies the kind of events it is interested in.

26
Update Protocols: Push or Pull
public void measurementsChanged ( ) {
setChanged(); We first call the setChanged() to
notifyObservers(); indicate that the state has changed.
}
We aren’t sending a data object with the
notifyObservers() call. The Observers are
aware of the subject and they will use that to
“pull” the latest information from the subject.

public void measurementsChanged ( ) {


setChanged();
notifyObservers(this);
}` A “push” method -- the modified
data is being pushed to the
observers.

27
Other places to find
Observer Pattern in Java
 Both JavaBeans and Swing also provide implementations of
the Observer pattern
 Look under the hood of JButton’s super class
AbstractButton
 Has many add/remove listener methods: allow you to add and
remove observers (called listeners in Swing)
 These “listeners” are available for various types of events that occur
on the Swing component
 Example: ActionListener lets you “listen in” on any types of actions
that might occur on a button -- like a button press.
 Also check out the PropertyChangeListener in JavaBeans

28
A Simple Example:
A “Life-Changing” Application
 Background:
 simple application with one button that says “Should I
do it”.
 When you click on the button the “listeners” get to
answer the question in any way they want.

 Code sample: implements 2 such listeners:


AngelListener and DevilListener

29
Implementing the Subject Interface
public class SwingObserverExample {
JFrame frame;
public static void main(String[] args) {
SwingObserverExample example = new SwingObserverExample();
example.go();
}
Setting up the listeners /
public void go() { observers of the button.
frame = new JFrame();
JButton button = new JButton("Should I do it");
button.addActionListener(new AngelListener());
button.addActionListener(new DevilListener());
frame.getContentPane().add(BorderLayout.CENTER, button);
// set frame properties here
}
the class definitions
class AngelListener implements ActionListener {
public void actionPerformed(ActionEvent event) { for the observers, that
System.out.println("Don’t do it, you might regretimplement
it!"); the
} actionPerformed()
} method and gets called
class DevilListener implements ActionListener {
public void actionPerformed(ActionEvent event) { when the state in the
System.out.println("Come on, do it!"); subject (button)
} changes.
}
}
30
A Simple Example: A “Life-Changing” Application

31
Summary
 OO Principle in play:
"Strive for loosely coupled designs between objects
that interact."
 Main points:
 The Observer pattern defines a one to many
relationship between objects
 Subjects (observables), update Observers using a
common interface
 Observers are loosely coupled in that the Observable
knows nothing about them, other than they implement
the Observer interface.
 You can push or pull data from the Observable when
using the pattern (“pull” is considered more correct)

32
Summary
 Don’t depend on a specific order of notification for your
Observers
 Java has several implementations of the Observer Pattern
including the general purpose java.util.Observable
 Watch out for issues with java.util.Observable
 Don’t be afraid to create our own version of the Observable
if needed
 Swing makes heavy use of the Observer pattern, as do
many GUI frameworks
 You find this pattern in other places as well including
JavaBeans and RMI.

33
1
Welcome to Starbuzz Coffee!
 Starbuzz Coffee has made a name for itself as the
fastest growing coffee shop.
 Because they have grown so quickly, they are
scrambling to update their ordering system to match
their beverage offerings….

2
Various types of BCOFFEE
 Beverage price
 HouseBlend: 20.000 đ
 Decaf: 17.000 đ
 Espresso: 26.000 đ
 DarkRoast: 22.000 đ
 Condiment price
 Milk: 5.000 đ
 Soy: 3.000 đ
 Mocha: 7.000 đ
 Whip: 9.000 đ

3
The First Design of the Coffee Shop
Beverage is an abstract
class, subclassed by all Beverage
beverages offered in the
- description
coffee shop.
+ getDescription() The cost() method is abstract;
+ cost() subclasses need to define their
// other useful methods own implementations.

HouseBlend DarkRoast Decaf Expresso

+ cost() + cost() + cost() + cost()

Each subclass implements cost() to return the cost of the beverage

4
Adding on…
 In addition to your coffee you can also ask for several condiments like
steamed milk, soy, mocha, … Starbuzz charges a bit for each of these so
they really need to get them built into the order system.
 First attempt …
Beverage
- description

Can you say “Class + getDescription()


+ cost()
Explosion” !!!! // other useful methods Each cost method computes the
cost of the coffee along with
other condiments in the order.

HouseBlend DarkRoast Decaf Expresso


DarkRoastWithSteamedMilkAndMocha
HouseBlendWithSteamedMilkandMocha
+ cost() + cost() + cost() + cost()
+ cost()
+ cost() DecafWithSteamedMilkAndMocha HouseBlendWithSteamedMilk
ExpressoWithWhipandSoy
+ cost() DarkRoastWithWhip+ cost()
+ cost()
DarkRoastWithSoyAndMocha
DarkRoastWithSteamedMilk
+ cost()

+ cost()
+ cost()
5
Question
 It is pretty obvious that Starbuzz has created a
maintenance nightmare for themselves.
 What happens when the price of milk goes up? Or
when they add a new caramel topping?
 What OO design principle(s) are they violating here?
 Encapsulate what varies
 Program through an interface not to an implementation
 Favor Composition over Inheritance

6
Alternatives to the Design?
Beverage
- description We add instance variables to represent
- milk whether or not each beverage has milk,
- soy soy, mocha and whip...
- mocha
- whip
Now we’ll implement cost() in Beverage
+ getDescription() (instead of keeping it abstract), so that it can
These get and set + cost() calculate the costs associated with the
+ hasMillk() condiments for a particular beverage instance.
the boolean values + setMillk()
for the condiments. + hasSoy() Subclasses will still override cost(),
+ setSoy()
// other but they will also invoke the super
version so that they can calculate the
total cost of the basic beverage plus
the costs of the added condiments.

HouseBlend DarkRoast Decaf Expresso

+ cost() + cost() + cost() + cost()

7
Sharpen your pencil

8
Is this ok?
 What requirements or other factors might change
that will impact this design?
1) Price changes for condiments will force us to alter the
existing code
2) New condiments will force us to add new methods
and alter the cost method in the superclass.
3) New beverages like iced tea. The iced tee class will still
inherit the methods like hasWhip().
4) What if a customer wants a double mocha?
What else?

9
The Open-Closed Principle
Classes should be open for extension,
but closed for modification.

 Our goal is to allow classes to be easily extended to


incorporate new behavior without modifying existing
code.
 What do we get if we accomplish this? Designs that are
resilient to change and flexible enough to take on new
functionality to meet changing requirements.

10
Meet the Decorator Pattern
 Decorating Coffee: We start with a beverage and
“decorate” it with the condiments at runtime.
 If a customer wants a Dark Roast with Mocha and
Whip we do the following:
1) Take a DarkRoast object
2) Decorate it with a Mocha object
3) Decorate it with a Whip object
4) Call the cost() method and rely on delegation to add
on the condiment costs.

How do you “decorate” and how does delegation come into this?
11
Constructing a drink order with Decorators
DarkRoast inherits from
cost() Beverage and has a cost()
method that computes the
1. Start with the DarkRoast object cost of the drink.

2. Customer wants Mocha, so we create a Mocha object and


wrap it around the DarkRoast.

cost()
cost() The Mocha object is a “decorator”. Its type
mirrors the object it is decorating, in this
case, a Beverage.
3. The customer also wants Whip, so we create a Whip
decorator and wrap Mocha with it.

cost() Whip is a decorator, so it also mirrors DarkRoast’s


cost() cost()
type and includes a cost() method.

12
Constructing a drink order with Decorators
4) Compute the cost for the customer.
 Do this by calling cost() on the outermost decorator, Whip, and
Whip is going to delegate computing cost to the objects it
decorates. Once it gets a cost, it will add on the cost of the Whip.
(2) Whip calls
cost() on Mocha
(1) First we call cost() on the (3) Mocha calls
outermost decorator Whip. cost() on DarkRoast

cost()
cost() cost()
1.29 0.10 1.19 0.99 (4) DarkRoast returns
its cost, 99 cents

(6) Whip adds its total, 10 cents,


to the result from Mocha, and (5) Mocha adds its cost, 20 cents, to the
returns the final result -- $1.29. result and returns the new total $1.19

13
So what do we know so far?
 Decorators have the same supertype as the objects that
they decorate.
 You can use one or more decorators to wrap an object.
 Given that the decorator has the same supertype as the
object it decorates, we can pass around a decorated object
in place of the original object.
 The decorator adds its own behavior either before and/or
after delegating to the object it decorates to do the job.
 Objects can be decorated at any time, so we can decorate
objects at runtime with as many decorators as we like.

Key point!
14
Decorator Pattern Defined
The Decorator Pattern attaches additional responsibilities to an object
dynamically. Decorators provide a flexible alternative to subclassing for
extending functionality.
defines the interface for Component
objects that can have
+ methodA()
responsibilities added to + methodB()
them dynamically. + other methods() maintains a reference to a Component object
and implement the same interface as the
component they are going to decorate.

defines an object ConcreteComponent Decorator


to which additional
responsibilities can + methodA() + methodA()
be attached. + methodB() + methodB()
+ other methods() + other methods()
can adds responsibilities
to the component.

ConcreteDecoratorA ConcreteDecoratorB
Decorators can - wrappedObject : Component - wrappedObject : Component
extend the state of - newState : Object
the component + methodA()
+ methodB() + methodA()
+ other methods() + methodB()
15
+ other methods()
Decorate the Beverages!
Beverage Beverage acts as our
- description abstract Component class
+ getDescription()
+ cost()
// other

HouseBlend DarkRoast CondimentDecorator

+ cost() + cost() + getDescription()

Decaf Expresso

+ cost() Milk Mocha


+ cost()
- beverage : Beverage - beverage : Beverage

The four concrete components, + getDescription() + getDescription()


one per coffee type. + cost() + cost()

Whip Soy
The condiment decorators. Notice
- beverage : Beverage - beverage : Beverage
they need to implement the cost()
as well as the getDescription(). + getDescription() + getDescription()
+ cost() + cost() 16
Some Real Code!
Beverage is an abstract class.
public abstract class Beverage { getDescription() method is
String description = "Unknown Beverage"; already implemented, but we
need to implement cost()
public String getDescription() { method in the subclasses.
return description;
}
public abstract double cost();
} We need to be interchangeable
with Beverage, so we extend
public abstract class CondimentDecorator the Beverage class.
extends Beverage {
public abstract String getDescription(); We are also going to require
} that the condiment decorators
reimplement the
getDescription() method.

17
Coding Beverages
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}
public double cost() {
return .99;
}
}

public class Espresso extends Beverage {


public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}

18
Coding Condiments
public class Mocha extends CondimentDecorator {
Beverage beverage;

public Mocha(Beverage beverage) {


this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost(); We want our description to say not
} only Dark Roast -- but to also include
} the item decorating each beverage
for instance: Dark Roast, Mocha.
Similarly, to compute the cost of the beverage
with Mocha, we first delegate to the object that
is being decorated, so that we can compute its
cost and then add in the cost of the Mocha.

19
Ordering Coffee
public class StarbuzzCoffee {
public static void main(String args[]) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()
+ " $" + beverage2.cost());
}
}

Output: Espresso $1.99


Dark Roast Coffee, Mocha, Mocha, Whip $1.49

20
Real World Decorators
 The java.io package uses the Decorator pattern!
Heres the abstract component InputStream
FilterInputStream is
an abstract decorator

FileInputStream StringBufferInputStream ByteArrayInputStream FilterInputStream

PushbackInputStream DataInputStream

These InputStreams are the LineNumberInputStream BufferedInputStream


ConcreteComponents. There
are a few more that are not
shown here.
Here are the concrete decorators.
21
The java.io Package (contd.)
 What is the typical set of objects that use decorators to add
functionality to reading data from a file?
1001
1110100
001010 A Text File
1010111
LineNumberInputStrea
m is also a concrete
decorator. It adds the
ability to count the line
numbers as it reads data.

FileInputStream is the component


that’s being decorated. The Java I/O
library supplies several components,
BufferedInputStream is a concrete including FileInputStream,
Decorator. BufferedInputStream adds behavior StringBufferInputStream, and others.
in two ways: it buffers input to improve All of these give us the base
performance, and also augments the interface component from which to read bytes.
with a new method readLine() for reading
character-based input, a line at a time.
22
Exercise your brains…
 How would you write a decorator that converts all
uppercase characters to lowercase in the input stream?

23
Writing your own Java I/O Decorator
public class LowerCaseInputStream extend the FilterInputStream
extends FilterInputStream { abstract decorator for all
InputStreams
public LowerCaseInputStream(InputStream in) {
super(in);
implement two read methods.
}
They take a byte (or an array of
bytes) and convert each byte to
public int read() throws IOException { lowercase.
int c = super.read();
return (c == -1 ? c : Character.toLowerCase((char)c));
}

public int read(byte[] b, int offset, int len)


throws IOException {
int result = super.read(b, offset, len);
for (int i = offset; i < offset+result; i++) {
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}
24
Test out your new Java I/O Decorator
public class InputTest {
public static void main(String[] args)
throws IOException {
int c; Set up the FileInputStream and decorate it, first
with a BufferedInputStream and then our brand
try {
new LowerCaseInputStream filter.
InputStream in =
new LowerCaseInputStream(
new BufferedInputStream(
new FileInputStream("test.txt")));
while((c = in.read()) >= 0) {
System.out.print((char)c);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

25
Code Demo
 Read a plain text file and compress it using the GZIP
format GZIP.java
 Read a compress file in the GZIP format and write it to
a plain text file UNGZIP.java

26
Compress text file
// Open the input file
String inFilename = "iliad10.txt";
FileInputStream input =
new FileInputStream(inFilename);

// Open the output file


String outFilename = "iliad10.gz";
GZIPOutputStream out = new GZIPOutputStream(
new FileOutputStream(outFilename));

// Transfer bytes from the output file to the compressed file


byte[] buf = new byte[1024];
int len;
while ((len = input.read(buf)) > 0) {
out.write(buf, 0, len);
}

// Close the file and stream


input.close();
out.close();
27
Decompress file
// Open the gzip file
String inFilename = "iliad10.gz";
GZIPInputStream gzipInputStream =
new GZIPInputStream(new FileInputStream(inFilename));
// Open the output file
String outFilename = "TheIliadByHomer";
OutputStream out = new FileOutputStream(outFilename);

// Transfer bytes from the compressed file to the output file


byte[] buf = new byte[1024];
int len;
while ((len = gzipInputStream.read(buf)) > 0) {
out.write(buf, 0, len);
for (int i = 0; i < len; i++)
System.out.print((char) buf[i]);
System.out.println();
}
// Close the file and stream
gzipInputStream.close();
out.close();
28
Decorating Text

29
Decorator – Non Software Example

30
The Constitution of Software Architects
 Encapsulate what varies
 Program through an interface not to an
implementation
 Favor Composition over Inheritance
 Classes should be open for extension but closed for
modification
 ?????????
 ?????????
 ...

31
Decorator Advantages/Disadvantages
 ++
 Provides a more flexible way to add responsibilities to a
class than by using inheritance, since it can add these
responsibilities to selected instances of the class
 Allows to customize a class without creating subclasses
high in the inheritance hierarchy.
 --
 A Decorator and its enclosed component are not
identical. Thus, tests for object types will fail.
 Decorators can lead to a system with “lots of little
objects” that all look alike to the programmer trying to
maintain the code

32
Summary
 Decorator patterns are based on the open-closed principle!
 We should allow behavior to be extended without the need to modify
existing code.
 The Decorator Pattern
 Provides an alternative to subclassing for extending behavior.
 Involves a set of decorator classes that are used to wrap concrete
components
 Decorator classes mirror the types of the components they decorate.
 Decorators change the behavior of their components by adding new
functionality before and/or after method calls to the component.
 You can wrap a component with any number of decorators.
 Decorators are typically transparent to the client of the component --
unless the client is relying on the component’s concrete type.
 Decorators can result in many small objects in our design, and overuse
can be complex!

33
"Baking with OO Goodness"

1
The Constitution of Software Architects
 Encapsulate what varies
 Program through an interface not to an
implementation
 Favor Composition over Inheritance
 Classes should be open for extension but closed for
modification
 ?????????
 ?????????
 ?????????
 ?????????
 ?????????

2
"new" = "concrete"
 Design Principle: "Program through an interface not
to an implementation"
 However, every time you do a "new" you need to deal
with a "concrete" class, not an abstraction.

Duck duck = new MallardDuck(); With a whole set of related concrete classes:
Duck duck;
if (picnic) duck = new MallardDuck ();
We want to use But we have to
else if (hunting)
interfaces to keep create an instance
code flexible of a concrete class duck = new DecoyDuck ( );
else if (inBathTub)
duck = new RubberDuck ( );
}

What's wrong with this? What principle is broken here?


3
What can you do?
 Principle: Identify the aspects that vary and separate
them from what stays the same.

 How might you take all the parts of your application


that instantiate concrete classes and separate or
encapsulate them from the rest of your application?

4
Identifying aspects that Vary
 Order pizza in a pizza store in cutting edge
Objectville!

Pizza orderPizza() { For flexibility it would be


Pizza pizza = new Pizza(); nice if this wasn’t concrete,
but we can’t instantiate
pizza.prepare() ; abstract classes!
pizza.bake();
pizza.cut();
pizza.box(); Prepare the pizza
return pizza;
}

5
Identifying aspects that Vary
 But you need more than one type of pizza:
Pizza orderPizza(String type) { Pass in the type of Pizza
Pizza pizza; to orderPizza( )
if (type.equals("cheese") { Instantiate based on type
pizza = new CheesePizza();
of pizza
} else if (type.equals("greek")) {
pizza = new GreekPizza();
} else if (type.equals("pepperoni") { Pizza
pizza = new PepperoniPizza();
} + prepare()
+ bake()
+ cut()
pizza.prepare() ; + box()
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
} CheesePizza GreekPizza PepperoniPizza

6
But the pressure is on to add more
pizza types….
 Need to add a couple trendy pizzas to their menu:
Clam and Veggie. Greek is not selling so well – so take
it out!

 What do you think would need to vary and what would


stay constant?

7
Modified orderPizza() Pizza orderPizza(String type) {
Pizza pizza;
if (type.equals("cheese") {
Pizza
pizza = new CheesePizza();
This is what
+ prepare() } else if (type.equals("greek")) {
varies
+ bake() pizza = new GreekPizza();
+ cut()
This code is
} else if (type.equals("pepperoni"){
+ box() not closed for
pizza = new PepperoniPizza();
modification!
} else if (type.equals("clam") {
pizza = new ClamPizza();
} else if (type.equals("veggie") {
CheesePizza PepperoniPizza
pizza = new VeggiePizza();
}
ClamPizza VeggiePizza pizza.prepare();
pizza.bake();
pizza.cut(); This is what we expect
pizza.box(); will stay the same
return pizza;
}

8
Encapsulating Object Creation
 Move the object creation out of the orderPizza() method.
 How?
 Move the creation code into a special purpose object that is
concerned with only creating pizzas

Pizza orderPizza(String type){ if (type.equals("cheese") {


Pizza pizza; pizza = new CheesePizza();
pull it out
} else if
(type.equals("pepperoni"){
pizza.prepare(); pizza = new PepperoniPizza();
pizza.bake(); } else if (type.equals("clam") {
pizza.cut(); pizza = new ClamPizza();
What’s going
pizza.box(); } else if (type.equals("veggie"){
to go here?
return pizza; pizza = new VeggiePizza();
} }

We place this code into a separate


object SimplePizzaFactory
9
Building a Simple Pizza Factory
Factories handle the details of the object creation.
public class SimplePizzaFactory {
public Pizza createPizza(String type){
Pizza pizza = null;
if (type.equals("cheese"){ Here’s code we plucked out
pizza = new CheesePizza(); of the orderPizza() method.
} else if (type.equals("pepperoni"){
pizza = new PepperoniPizza();
} else if (type.equals("clam"){ Code is still parameterized
pizza = new ClamPizza(); by the type of pizza, just like
} else if (type.equals("veggie"){ the original code.
pizza = new VeggiePizza();
}
return pizza;
}
}

Could this method be made static?


10
Reworking the PizzaStore class
public class PizzaStore { PizzaStore has a
SimplePizzaFactory factory; reference to the factory
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
} PizzaStore gets the
public Pizza orderPizza(String type){ factory passed in the
Pizza pizza; constructor
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake(); New operator replaced
pizza.cut(); by create method!
pizza.box();
return pizza;
}
}

11
Why is this better?
 SimplePizzaFactory may have many more clients
than orderPizza() method
 PizzaShopMenu, HomeDelivery etc.
 Client code does not have any concrete classes
anymore!!

 SimpleFactory is not really a design pattern but the


actual Factory patterns are based on it!

12
SimpleFactory Pattern
This is the factory where we create pizzas; Abstract class with some
this should be the only part of our application helpful implementations
that refers to concrete Pizza classes. that can be overridden.
Pizza
PizzaStore SimplePizzaFactory create Product of
+ prepare() the factory
+ bake() (abstract)
+ createPizza() + createPizza() + cut()
Client of the factory. create method sometimes + box()
Goes through factory to declared static.
get instances of Pizza

CheesePizza PepperoniPizza
VeggiePizza ClamPizza

Concrete products. Each product needs


to implement the Pizza interface.

13
Onwards with the Pizza Franchise
 Franchises in different cities
 Must ensure quality of pizza
 Must account for regional differences (NY, Chicago..)
 Want franchise store to leverage your PizzaStore code -
-> pizzas are prepared the same way
 NY needs a factory that makes NY style pizza
 Chicago needs a factory that makes Chicago style pizza

 One approach --> SimpleFactory

14
Applying SimpleFactory
PizzaStore Pizza
PizzaFactory name : String
factory : PizzaFactory
dough : String
orderPizza() createPizza() sauce : String
toppings : ArrayList

prepare()
bake()
ChicagoStylePizzaFactory cut()
box()
createPizza()

NYStylePizzaFactory
NYStyleCheesePizza ChicagoStyleCheesePizza
createPizza() NYStylePepperoniPizza ChicagoStylePepperoniPizza
NYStyleClamPizza ChicagoStyleClamPizza
NYStyleVeggiePizza ChicagoStyleVeggiePizza

create
create

15
Applying SimpleFactory Pattern
NYPizzaFactory nyFactory = new NYPizzaFactory(); Here we create a factory for
PizzaStore nyStore = new PizzaStore(nyFactory); making NY style pizza
nystore.order("Veggie");
Then we create a
ChicagoPizzaFactory cFactory = new ChicagoPizzaFactory(); PizzaStore and pass it a
PizzaStore cStore = new PizzaStore(cFactory); reference to the NY factory
cStore.order("Veggie");
…and when we make pizzas
we get NY style pizzas
Issues:
 Franchises using your factory to create pizza, but using homegrown
procedures for baking etc.
 Yet, each franchise “needs room for adding own improvements”
 You don’t want to know what they put on their pizza - detail that should be
“exposed” only to the individual stores. Yet you want to have some control
(quality control!)
 What is needed is a framework that ties the store and pizza creation
together, yet allows for flexibility.

16
A Framework
 Need a mechanism to “localize” all pizza making activities
to the PizzaStore class and yet give franchises freedom to
have their own regional style!
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Now createPizza is back to
Pizza pizza = createPizza(type); being a call to a method in
the PizzaStore rather than a
pizza.prepare(); Factory object!
pizza.bake();
pizza.cut(); All this is the same. Break out
pizza.box(); into orderPizza() method.
return pizza;
}
Our factory method
is now abstract in
abstract Pizza createPizza(String item);
PizzaStore.
}

Allows each individual subclass to decide which Factory to invoke.


All subclasses MUST implement the createPizza method.
17
Allowing the subclasses to decide…
If franchise wants NY style pizzas PizzaStore
for its customers, it uses the NY
subclass, which has its own + createPizza()
createPizza() method, creating + orderPizza()
NY style pizzas.

NYStylePizzaStore ChicagoStylePizzaStore

+ createPizza() + createPizza()

createPizza() returns a
Each subclass overrides the createPizza() Pizza and the subclass is
method, while all subclasses make use of fully responsible for which
the orderPizza() method defined in the concrete Pizza it instantiates
PizzaStore.

18
Let's make a PizzaStore
extends PizzaStore, so it inherits
the orderPizza() method

public class NYPizzaStore extends PizzaStore {


Pizza createPizza(String item) {
implement createPizza(), since
if (item.equals("cheese")) { it is abstract in PizzaStore
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
Here’s where the concrete
return new NYStyleClamPizza(); classes are being created!
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}
}

Note: orderPizza() method in superclass has no clue which Pizza we


are creating. It only knows it can prepare, bake, cut and box it!

19
A Factory Method Up Close!
 A “Factory” method handles object creation and
encapsulates it in a subclass. This decouples the client code
in the superclass from the object creation code in the
subclass.
A factory method may or may
A factory method is abstract so not be parameterized to
the subclasses are counted on select among several
to handle object creation. variations of a product.

abstract Product factoryMethod(String type)

A factory method returns a Product A factory method isolates the client (the code
that is typically used within methods in the superclass, like orderPizza()) from
defined in the superclass. knowing what kind of concrete Product is
actually created.

20
Factory Method Pattern
 All factory patterns encapsulate “object creation”
 Factory method pattern encapsulates object creation
by letting subclasses decide what objects to create.
 Who are the players in this pattern?

21
Factory Method Pattern Defined
The Factory Method Pattern defines an interface for creating an object
but lets the subclasses decide which class instantiate. Factory method
lets a class defer instantiation to subclasses.
contains the implementations
The abstract factoryMethod() is what
for all the methods to
all Creator subclasses must implement.
manipulate the products, except
for the factory method!
Creator
defines the Product
... + factoryMethod() interface
product=factoryMethod(); + anOperation() of objects
... the factory
method
creates

implements the ConcreteCreator <<create>>


factoryMethod() that actually ConcreteProduct
produces the products.
+ factoryMethod()

return new ConcreteProduct();


22
Advantages/Disadvantages
 ++
 Eliminates the need to bind application-specific classes into your
code
 Provides hooks for subclassing. Creating objects inside a class with a
factory method is always more flexible than creating an object
directly.
 This method gives subclasses a hook for providing an extended
version of an object
 Connects parallel heirarchies. Factory method localises knowledge
of which classes belong together. Parallel class hierarchies result
when a class delegates some of its responsibilities to a separate
class.
 --
 Clients might have to subclass the Creator class just to create a
particular Concreate object.

23
The Players!
Notice the parallel class
hierarchies: both have abstract The Creator Classes
The Product Classes classes that are extended by
PizzaStore
Pizza concrete classes, which know
about specific implementations
+ createPizza()
for NY and Chicago. + orderPizza()

NYStyleCheesePizza CStyleCheesePizza
NYStylePizzaStore
NYStylePepperoniPizza CStylePepperoniPizza
NYStyleClamPizza CStyleClamPizza + createPizza()
NYStyleVeggiePizza CStyleVeggiePizza
ChicagoStylePizzaStore

+ createPizza()
NYStylePizzaStore encapsulate all
the knowledge about how to make
ChicagoStylePizzaStore encapsulate all
NY Style Pizzas
the knowledge about how to make
Chicago Style Pizzas

Factory method is key to encapsulating this knowledge! 24


Pizza class
public abstract class Pizza {
String name; Each pizza has a name, a type of dough, a
String dough; type of sauce, and a set of toppings
String sauce;
ArrayList toppings = new ArrayList();
void prepare() { Abstract class
System.out.println("Preparing " + name); provides some basic
System.out.println("Tossing dough..."); defaults for baking,
System.out.println("Adding sauce...");
cutting and boxing
System.out.println("Adding toppings: ");
for (int i = 0; i < toppings.size(); i++) {
System.out.println(" " + toppings.get(i)); Preparation follows a
} number of steps in a
} particular sequence
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");
}
public String getName() {
return name;
}
}
25
New York and Chicago style cheese pizzas
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza() {
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
} Each Pizza type has
} its own style sauce,
dough and toppings
public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza() {
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
The Chicago Pizza overides cut() method
so that the pieces are cut into squares
26
Test Drive
public class PizzaTestDrive {
public static void main(String[] args) {

PizzaStore nyStore = new NYPizzaStore();


PizzaStore chicagoStore = new ChicagoPizzaStore();

Pizza pizza = nyStore.orderPizza("cheese");


System.out.println("Ethan ordered a " +
pizza.getName() + "\n");

pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " +
pizza.getName() + "\n");

// ...

}
}

27
What we have learned from Factory Method
 First of all let’s take a look on what we tried to avoid
public class DependentPizzaStore {
public Pizza createPizza(String style, String type){
Pizza pizza = null;
if (style.equals("NY")) {
if (type.equals("cheese")) {
pizza = new NYStyleCheesePizza();
} else if (type.equals("veggie")) {
pizza = new NYStyleVeggiePizza();
...
} else if (style.equals("Chicago")) {
if (type.equals("cheese")) {
pizza = new ChicagoStyleCheesePizza();
} else if (type.equals("veggie")) {
pizza = new ChicagoStyleVeggiePizza();
...
}
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
28
29
Design Principle

Depend upon abstractions. Do not depend upon


concrete classes.

30
DIP explained
Depend upon abstractions.
Do not depend upon
concrete classes.

High-level components should not


depend on low level components;
they should both depend on
abstractions

PizzaStore is ”high level component”


Pizzas are ”low level components”

31
Guidlines to follow the DIP
 No variable should hold a reference to a concrete class
 If you use new you are holding a reference to a concrete class. Use a
factory to get around that
 No class should derive from a concrete class
 If you derive from a concrete class, you’re depending on a concrete
class. Derive from an abstraction like an interface or an abstract
class.
 No method should override an implemented method of
any of its base classes
 If you override an implemented method, then you base class wasn’t
really an abstraction to start with. Those methods implemented in
the base class are meant to be shared by all your subclasses.

32
Meanwhile, back at the PizzaStore….
 Things are going good, but you have learned that a few
franchises are substituting inferior ingredients -> bringing
down the Objectville name!

 How are you going to ensure each factory is using quality


ingredients?
 You are going to build a factory that produces them and ships them
to your franchises!
 One problem: franchises are located in different regions so what is
red sauce in NY is not red sauce in Chicago!
 So: same product families (dough, cheese, sauce etc.) but
different implementations based on region.

33
Building the Ingredient Factory
 Ingredient factory: creates each ingredient in the
ingredient family (but does not handle regional differences
yet!)

public interface PizzaIngredientFactory {


public Dough createDough(); For each ingredient we define a
public Sauce createSauce(); create method in our interface.
public Cheese createCheese();
If we had some common
public Veggies[] createVeggies(); “machinery” to implement in each
public Pepperoni createPepperoni(); instance of factory, we could have
public Clams createClam(); made this abstract instead.
}
Lots of new classes here, one per
ingredient

34
What to do next?
 Build a factory for each region. To do this, create a
subclass of PizzaIngredientFactory that implements
each create method.
 Implement a set of ingredient classes to be used with
the factory, like RedPeppers, ThickCrustDough, etc.
These classes can be shared among regions where
appropriate.
 Then we still need to hook all this up by working our
new ingredient factories into the old PizzaStore
code.

35
Build a factory for each region
<<Interface>>
PizzaIngredientFactory

createDough()
createSauce()
createVeggies()
createCheese()
createPepperoni()
createClams()

NYPizzaIngredientFactory ChicagoPizzaIngredientFactory

createDough() createDough()
createSauce() createSauce()
createVeggies() createVeggies()
createCheese() createCheese()
createPepperoni() createPepperoni()
createClams() createClams()

36
Build a factory for New york …
<<Interface>> <<Interface>> <<Interface>>
PizzaIngredientFactory Dough Sauce

createDough()
createSauce()
createVeggies() ThinCrustDough
createCheese() MarinaraSauce
createPepperoni() ThickCrustDough PlumTomatoSauce
createClams()

<<Interface>>
NYPizzaIngredientFactory
<<Interface>> Veggies
Cheese
createDough()
createSauce()
createVeggies()
createCheese() Garlic BlackOlives
createPepperoni() Onion
createClams() ReggianoCheese Spinach
Mushroom
MozzarellaCheese Eggplant
RedPepper

37
(1) The New York Ingredient Factory
public class NYPizzaIngredientFactory
implements PizzaIngredientFactory {
public Dough createDough() {
return new ThinCrustDough();
The NY ingredient factory implements
}
the interface for all ingredient factories
public Sauce createSauce() {
return new MarinaraSauce();
For each ingredient in the
}
ingredient family, we create the
public Cheese createCheese() {
NY version.
return new ReggianoCheese();
}
public Veggies[] createVeggies() {
Veggies veggies[] =
{ new Garlic(), new Onion(),
new Mushroom(), new RedPepper() };
return veggies;
}
// other ingredients
}

38
Implement a set of ingredient classes
<<Interface>> <<Interface>> <<Interface>>
Dough Sauce Pepperoni

ThinCrustDough MarinaraSauce SlicedPepperoni


ThickCrustDough PlumTomatoSauce

<<Interface>>
Veggies
<<Interface>> <<Interface>>
Cheese Clams

Garlic BlackOlives
Onion Spinach
FreshClams Mushroom
ReggianoCheese Eggplant
MozzarellaCheese FrozenClams RedPepper

39
Reworking the Pizzas
Pizza <<Interface>> <<Interface>> <<Interface>>
Dough Sauce Pepperoni
name : String
dough : Dough
saugh : Sauce
veggies : Veggies[]
cheese : Cheese ThinCrustDough MarinaraSauce SlicedPepperoni
pepperoni : Pepperoni ThickCrustDough PlumTomatoSauce
clam : Clams

prepare() <<Interface>>
bake() Veggies
cut()
box() <<Interface>> <<Interface>>
Cheese Clams

Garlic BlackOlives
Onion Spinach
FreshClams Mushroom
ReggianoCheese Eggplant
MozzarellaCheese FrozenClams RedPepper

40
Reworking the Pizzas
public abstract class Pizza {
String name;
Dough dough; Each pizza holds a set of ingredients
Sauce sauce; that are used in its prep.
Veggies veggies[];
Cheese cheese; The prepare() method is abstract.
Pepperoni pepperoni; This is where we are going to
Clams clam; collect the ingredients needed for
the pizza which will come from the
abstract void prepare();
ingredient factory.
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");
}
void setName(String name) { this.name = name; }
String getName() { return name; }
}
41
Hook pizza working ingredient factories
Pizza
name : String
dough : Dough
saugh : Sauce
veggies : Veggies[]
cheese : Cheese
pepperoni : Pepperoni
clam : Clams

prepare()
bake()
cut()
box()

ClamPizza
CheesePizza factory : PizzaIngredientFactory
factory : PizzaIngredientFactory prepare() PepperoniPizza
factory : PizzaIngredientFactory
prepare() VeggiePizza
factory : PizzaIngredientFactory prepare()
prepare()

42
Reworking the Pizzas (cont)
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;

public CheesePizza(PizzaIngredientFactory ingredientFactory) {


this.ingredientFactory = ingredientFactory;
}
To make a pizza now, we
need a factory to provide the
void prepare() {
ingredients. So each class
System.out.println("Preparing " + name);
gets a factory passed into its
dough = ingredientFactory.createDough();
constructor, and its stored
sauce = ingredientFactory.createSauce();
in an instance variable.
cheese = ingredientFactory.createCheese();
}
}

The prepare ( ) method steps through the


creating a cheese pizza, and each time it
needs an ingredient, it asks the factory to
produce it.

43
Code Up Close!
The createSauce () method returns
We are setting the pizza the sauce that is used in its region.
instance variable to refer to the If this is NY ingredient factory, then
specific sauce used in this pizza we get marinara sauce.

sauce = ingredientFactory.createSauce();

This is the ingredient Factory.


The pizza does not care which
factory is used, as long as it is
an ingredient factory.

44
Revisiting the Pizza Store
The NY Store is composed
public class NYPizzaStore extends PizzaStore { with a NY pizza ingredient
factory. This will be used to
protected Pizza createPizza(String item) { produce the ingredients for
Pizza pizza = null; all NY style pizzas.
PizzaIngredientFactory ingredientFactory =
new NYPizzaIngredientFactory();
We now pass
if (item.equals("cheese")) { each pizza the
pizza = new CheesePizza(ingredientFactory); factory that
pizza.setName("New York Style Cheese Pizza"); should be used
} else if (item.equals("veggie")) { to produce its
pizza = new VeggiePizza(ingredientFactory); ingredients.
pizza.setName("New York Style Veggie Pizza");
} // same for all other pizza types.
return pizza;
}
} For each type of pizza we instantiate a
new Pizza and give it the factory that it
needs to get its ingredients.

45
Defines the
What have we done? interface

 We provided a means of creating a


family of ingredients for pizzas by Objectville
Abstract
introducing a new type of factory IngredientFactory
called -- Abstract Factory.
 Abstract Factory:
 Gives an interface for creating a
family of products.
 By writing code that uses this
interface we decouple our code
from the actual factory that
creates the products.
 Allows us to implements a variety NY Chicago
of factories that produce products
meant for different contexts.
 Decoupling --> enables Provides
substitution of different factories implementations
to get different behaviors. for products
Pizza Store

Pizza made with ingredients produced by the


concrete factory 46
Abstract Factory Pattern
 Intent
 Provide an interface for creating families of related or dependent
objects without specifying their concrete classes.
 Applicability
 When clients cannot anticipate groups of classes to instantiate
 A system should be independent of how its products are created,
composed, and represented.
 A system should be configured with one of multiple families of
products.
 A family of related product objects is designed to be used together,
and you need to enforce this constraint.
 You want to provide a class library of products, and you want to
reveal just their interfaces, not their implementations.

47
Structure
The AbstractFactory This is the
defines the interface product family.
that all Concrete Each concrete
factories must factory can
implement, produce an entire
set of objects.

The concrete factories implement


the different product families. To
create a product, the client uses
one of these factories, so it never
has to instantiate a product object.

48
Summary
 All factories encapsulate object creation
 Simple factory, while not a bona fide design pattern, is
a simple way to decouple your clients from concrete
classes.
 Factory method relies on inheritance: object creation
is delegated to subclasses which implement the factory
method to create objects
 Abstract Factory relies on object composition: object
creation is implemented in methods exposed in the
factory interface.

49
Summary
 All factory methods promote loose coupling by reducing
the dependency of your application on concrete classes.
 The intent of Factory method is to allow a class to defer
instantiation to its subclasses.
 The intent of the Abstract Factory is to create families of
related objects without having to depend on their concrete
classes.
 The Dependency Inversion principle guides us to avoid
dependencies on concrete types and to strive for
abstractions.
 Factories are a powerful technique for coding to
abstractions, not concrete classes.

50
How important is it to use
Factories?
 Factories are powerful tools
 Great benefit when trying to conform to DIP
 Heuristics for use:
 Strict interpretation -- use factories for every volatile
class
 But don’t use factories for everything: too extreme
 Initially - don’t start out using factories, add them in as
you see the need for them
 Might need to “spoof” objects during testing
 Remember: Factories are a complexity that can often
be avoided in the early phases
 They unnecessarily complicate designs!

51
“One of a Kind Objects”

1
Singleton: What is this?
 How to instantiate just one object - one and only one!
 Why?
 Many objects we need only one of: thread pools, caches, dialog
boxes, objects that handle preferences and registry settings etc.
 If more than one instantiated: Incorrect program behavior, overuse
of resources, inconsistent results
 Alternatives:
 Use a global variable:
 Downside: assign an object to a global variable, then that object might
be created when application begins. If application never ends up using it
and object is resource intensive --> waste!
 Use a static variable
 Downside: how do you prevent creation of more than one class object?

2
The Little Singleton
How would you create a single object? new MyClass();
And what if another object wanted to Yes, why not.
create a MyClass? Could it call new on
MyClass again?
Can we always instantiate a class one or Yes. Caveat: Only if it is public class
more times?
And if not? If it's not a public class, only
classes in the same package can
instantiate it, but they can
instantiate it more than once.
Is this possible? Yes. It is a legal definition
public MyClass {
private MyClass() { }
}
What does it mean? A class that can’t be instantiated
because it has a private constructor
3
The Little Singleton (con't)
Is there any class that could use a private MyClass is the only code
constructor? that could call it.
What does this mean? We can call the static
public MyClass { method:
public static MyClass getInstance() { } MyClass.getInstance()
}
Now, can I instantiate a MyClass? Yes
public MyClass {
private MyClass() { }
public static MyClass getInstance() {
return new MyClass();
}
}
How you would create a MyClass object now? MyClass.getInstance()
Can you create now more than one MyClass? Yes, why not?

4
The Little Singleton (con't)

But I would like public MyClass {


to have only private static MyClass oneClass;
one MyClass. private MyClass() { }
How you do it?
public static MyClass getInstance() {
if (oneClass == null) {
oneClass = new MyClass();
}
return oneClass;
}
}

5
The Classic Singleton Pattern
We have a static variable to
hold our one instance of the
class Singleton.
public class Singleton {
private static Singleton uniqueInstance;
// other useful instance variables
Constructor is declared
private Singleton() { private; only singleton can
} instantiate this class!

public static Singleton getInstance() {


if (uniqueInstance == null) { The getInstance() method
uniqueInstance = new Singleton(); gives us a way to instantiate
} the class and also return an
return uniqueInstance; instance of it.
}

// other useful methods


} Of course, Singleton is a regular class so it
has other useful instances and methods.

6
Code Up Close
uniqueInstance holds our ONE If uniqueInstance is null, then we
instance; it is a static variable haven’t created the instance yet…

if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;

… and if it doesn’t exist, we


If uniqueInstance wasn’t null, then it was instantiate Singleton through its
previously created. We just fall through to private constructor and assign it
the return statement. In either case, we to the uniqueInstance.
have an instance and we return it. Note that if we never need the
uniqueInstance, it never gets
created --> lazy instantiation.

7
Singleton Pattern Defined
The Singleton Pattern ensures a class has only one
instance, and provides a global point of access to it.

The getInstance() method The uniqueInstance


is static, which means it is Singleton class variable holds
a class method, so you our one and only one
can conveniently access static uniqueInstance instance of Singleton.
this method anywhere in // other useful variables
your code using
Singleton.getInstance(). static getInstance()
We get benefits like lazy // other methods
instantiation from the
Singleton.
A class implementing a Singleton Pattern is
more than a Singleton; it is a general purpose
class with its own set of data and methods.

8
Computer controled chocolate boiler
public class ChocolateBoiler { The job of boiler is to take in chocolate and
private boolean empty; milk, bring them to a boil, and then pass them
private boolean boiled;
public ChocolateBoiler() { on to the next phrase of making the bars
empty = true; boiled = false;
}
To fill the boiler it must be
public void fill() {
if (isEmpty()) { empty, and, once it's full, we
empty = false; set the empty and boiled flags
boiled = false;
// fill the boiler with a milk/chocolate mixture
} To drain the boiler it must be full (not
}
public void drain() { empty) and also boiled. Once it is
if (!isEmpty() && isBoiled()) { drained we set empty back to true
// drain the boiled milk and chocolate
empty = true;
}
To boil the mixture, the boiler has to
}
public void boil() { be full and not already boiled. Once it
if (!isEmpty() && !isBoiled()) { is boiled we set boiled flag to true
// bring the contents to a boil
boiled = true;
}
}
public boolean isEmpty() { return empty; }
public boolean isBoiled() { return boiled; }
} 9
Turning ChocolateBoiler into Singleton
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
private static ChocolateBoiler uniqueInstance;

private ChocolateBoiler(){
empty = true;
boiled = false;
}
public static ChocolateBoiler getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
public void fill() {
...
}
10
Houston, we have a problem….
 We improved the Chocolate Boiler code with the
Singleton pattern and we added some optimizations to
the Chocolate Boiler Controller that makes use of
multiple threads
 Ugh… the Chocolate Boiler’s fill() method was able to
start filling the boiler even though a batch of milk and
chocolate was already boiling! That’s 500 gallons of
milk and chocolate spilled.
 Could the addition of threads have caused this?

11
Be the JVM
 We have two threads each executing this code:
ChocolateBoiler boiler = ChocolateBoiler.getInstance();
boiler.fill();
boiler.boil();
boiler.drain();

 Could the two threads get hold of different boiler


objects?

public static ChocolateBoiler getInstance() {


if (uniqueInstance == null) {
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}

12
What happened? Value of
Thread 1 Thread 2 uniqueC

ChocolateBoiler getInstance() null

ChocolateBoiler getInstance() null

if (uniqueC == null){ null

if (uniqueC == null){ null

uniqueC = new ChocolateBoiler(); object1

return = uniqueC; object1

uniqueC = new ChocolateBoiler(); object2

return = uniqueC; object2

13
Dealing with Multi-threading
 Easy fix: make getInstance() a synchronized method
public class Singleton {
Adding the synchronized keyword
private static Singleton uniqueInstance;
force every thread to wait its turn
// other useful instance variables here
before it can enter the method.
That is, no two threads may enter
private Singleton() {}
the method at the same time.
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
// other useful methods here
}

This fixes the problem, but synchronization is expensive; is this really an issue?
Synchronization is really only needed the first time through this method.
Once we have created the first Singleton instance, we have no further need to
synchronize this method.
14
Can we improve multithreading?
1. Do nothing if the performance of getInstance() isn’t
critical to your application. (remember that synchronizing
can decrease performance by a factor of 100)
2. Move to an eagerly created instance rather than a lazily
created one. Go ahead and create an instance of
Singleton in a static initializer. This
code is guaranteed to be thread safe!
public class Singleton {
private static Singleton uniqueInstance = new Singleton();

private Singleton() {}

public static Singleton getInstance() {


return uniqueInstance;
} We’ve already got an
} instance, so just return it.

15
Can we improve multithreading?
 Use “double-checked locking” to reduce the use of
synchronization in getInstance() If performance is an issue
then this method can
public class Singleton { drastically reduce overhead!
Check for an
instance and if private volatile static Singleton uniqueInstance;
there isn’t one,
enter the private Singleton() {}
synchronized public static Singleton getInstance() { Note we only
block. if (uniqueInstance == null) { synchronize the
synchronized (Singleton.class) { first time through.
if (uniqueInstance == null) {
The volatile keyword uniqueInstance = new Singleton();
ensures that multiple }
threads handle }
uniqueInstance }
variable correctly return uniqueInstance;
when it is being }
initialized to the } Once in the block, check again if
Singleton instance. null. If so create instance.

16
Summary
 The Singleton Pattern ensures you have at most one instance of a class
in your application
 The Singleton Pattern also provides a global access point to that
instance.
 Java’s implementation of the Singleton Pattern makes use of a private
constructor, a static method combined with a static variable
 Examine your performance and resource constraints and carefully
choose an appropriate Singleton implementation for multi-threaded
applications.
 Beware of double-checked locking implementation -- it is not thread-
safe pre JDK 1.5
 Be careful if you are using multiple class loaders -- this can defeat the
purpose of the Singleton implementation
 If you are using a JVM earlier than 1.2, you’ll need to create a registry of
Singletons to defeat the garbage collector.

17
Putting a Square Peg in a Round Hole!

1
What is Adapters
 Real world is full of them!

2
Object oriented adapters
 Scenario:
 you have an existing software system that you need to
work a new vendor library into, but the new vendor
designed their interfaces differently than the last vendor.

Your Existing Vendor


System Class

Their interface doesn’t match


the one you’ve written your code
against. Not going to work!

 What to do? Write a class that adapts the new vendor


interface into the one you’re expecting.
3
Object oriented adapters
The adapter And talks to the
implements the vendor interface to
interface your service your requests
classes expect

Your Vendor
Adapter
Existing Class
System

Your Vendor
Adapter
Existing Class
System

No code New code No code


changes changes

4
The Adapter Pattern - Intent
 The Adapter Pattern converts the interface of a class into
another interface the clients expect. Adapter lets classes
work together that couldn’t otherwise because of
incompatible interfaces.
Full of good OO design principles:
- Use of object composition
- Pattern binds the client to an
interface and not an implementation

The client sees only the


Target interface. The Adapter implements the
target interface

All requests get


Adapter is composed delegated to the
with the Adaptee Adaptee
Object Adapter
5
Object and Class Adapters
 There are two types of Adapters
 Object Adapter : use composition to adaptive the adaptee.
 Class Adapter : use inheritance.

Class Adapter

6
Applicability
 Use the Adapter pattern when
 want to use an existing class, and its interface does not
match the one you need.
 want to create a reusable class that cooperates with
unrelated or unforeseen classes that don't necessarily
have compatible interfaces.
 Class and object adapters have different trade-offs.
 A class adapter won't work when we want to adapt a
class and all its subclasses.
 An object adapter lets a single Adapter work with the
Adaptee itself and all of its subclasses (if any).

7
Example
Target interface Adaptee

Turkey has a incompatible


interface with Duck. We’d
like to use some Turkey as
Duck

8
Write Adapter
Target interface Adaptee
implements the
interface of the
Target, and get a
reference to adaptee

9
Turkey world code
public interface Turkey {
public void gobble();
public void fly();
}

public class WildTurkey implements Turkey {

public void gobble() {


System.out.println("Gobble gobble");
}

public void fly() {


System.out.println("I'm flying a short distance");
}
}

10
Duck and TurkeyAdapter
public interface Duck {
public void quack();
public void fly();
}
public class TurkeyAdapter implements Duck {
Turkey turkey;
public TurkeyAdapter(Turkey turkey) {
this.turkey = turkey;
}
public void quack() {
turkey.gobble();
}
public void fly() {
for(int i=0; i < 5; i++) {
turkey.fly();
}
}
}
11
Test Drive
public class DuckTestDrive {
public static void main(String[] args) {
WildTurkey turkey = new WildTurkey();
Duck turkeyAdapter = new TurkeyAdapter(turkey);

System.out.println("The Turkey says...");


turkey.gobble();
turkey.fly();
System.out.println("\nThe TurkeyAdapter says...");
turkeyAdapter.quack();
turkeyAdapter.fly(); The Turkey says...
Gobble gobble
}
I'm flying a short distance
}
The TurkeyAdapter says...
Gobble gobble
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
I'm flying a short distance
12
Using two-way adapters to provide transparency

13
Example: Adapting an Enumeration to
an Iterator
Target interface Adaptee interface

We are making the Enumeration in your old code look like Iterator for your
new code.

14
Example: Adapting an Enumeration
to an Iterator

EnumerationIterator
is the Adapter A class implementing the
Enumeration interface is
the adaptee.

15
Summary
 When you need to use an existing class and its interface is
not the one you need, use an adapter.
 An adapter changes an interface into one a client expects.
 Implementing an adapter may require little work or a great
deal of work depending on the size and complexity of the
target interface.
 There are two forms of adapter patterns: object and class
adapters. Class adapters require multiple inheritance.
 An adapter wraps an object to change its interface, a
decorator wraps an object to add new behaviors and
responsibilities.

16
Encapsulating Algorithms

1
Time for some more caffeine ...
Starbuzz Coffee Barista Training Manual
Baristas! Please follow these recipes precisely when preparing
Starbuzz beverages.

Starbuzz Coffee Recipe Starbuzz Tea Recipe


(1) Boil some water • Boil some water
(2) Brew coffee in boiling water • Steep tea in boiling water
(3) Pour coffee in cup • Pour tea in cup
(4) Add sugar and milk • Add lemon

The recipe for


coffee and tea are
very similar!

2
Whipping up some Coffee in Java
public class Coffee {

void prepareRecipe() {
boilWater(); Recipe for coffee - each step is
brewCoffeeGrinds(); implemented as a separate method.
pourInCup();
addSugarAndMilk();
}

public void boilWater() { Each of these methods


System.out.println("Boiling water"); implements one step of
} the algorithm.
public void brewCoffeeGrinds() {
System.out.println("Dripping Coffee through filter");
}

public void pourInCup() {


System.out.println("Pouring into cup");
}

public void addSugarAndMilk() {


System.out.println("Adding Sugar and Milk");
}
}
3
And now for the Tea …
public class Tea {
void prepareRecipe() {
boilWater(); Very similar to the
steepTeaBag(); coffee - 2nd and 4th
pourInCup(); steps are different.
addLemon();
}
public void boilWater() { These methods are
System.out.println("Boiling water"); exactly the same as
} the are in Coffee
public void steepTeaBag() {
System.out.println("Steeping the tea");
}
public void pourInCup() { These methods are
System.out.println("Pouring into cup"); specialized to Tea
}
public void addLemon() {
System.out.println("Adding Lemon");
}
}

We have code duplication - that’s a good sign that we need to clean up


the design. We should abstract the commonality into a base class since
coffee and tea are so similar, right?
4
Sir, may I abstract your Coffee, Tea?
CaffeineBeverage
The boilWater() and
The prepareRecipe()
pourInCup() are shared
method differs in prepareRecipe()
by both subclasses, so
each subclass, so it is boilWater()
defined in the superclass.
defined as abstract. pourInCup()

Coffee Tea Each subclass overrides


the prepareRecipe()
prepareRecipe() prepareRecipe() method and implements its
brewCoffeeGrinds() steepTeaBag() own recipe.
addSugarAndMilk() addLemon()

The methods specific to Coffee


and Tea stay in the subclasses.

Is this a good redesign? Are we overlooking some other commonality?


What are other ways that Coffee and Tea are similar?
5
What else do they have in common?
 Both the recipes follow the same algorithm:
1. Boil some water
2. Use hot water to extract the tea or coffee
3. Pour the resulting beverage into a cup
4. Add the appropriate condiments to the beverage.

These two are These aren’t abstracted but


already abstracted are the same, they just apply
into the base class. to different beverages.

Can we abstract prepareRecipe() too? Yes ...

6
Abstracting PrepareRecipe()
 Provide a common interface for the different methods
 Problem : Coffee uses brewCoffeeGrinds() and
addSugarAndMilk() methods while Tea uses steepTeaBag() and
addLemon() methods
 Steeping and brewing are pretty analogous – so a common interface
may be the ticket: brew() and addCondiments()
public class Coffee { public class Tea {
void prepareRecipe() { void prepareRecipe() {
boilWater(); boilWater();
brewCoffeeGrinds(); steepTeaBag();
pourInCup(); pourInCup();
addSugarAndMilk(); addLemon();
} }

public abstract class CaffeineBeverage {


abstract void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
} 7
Abstracting prepareRecipe()
CaffeineBeverage
CaffeineBeverage
prepareRecipe()
prepareRecipe()
boilWater() boilWater()
pourInCup() brew()
pourInCup()
addCondiments()

Coffee Tea
Coffee Tea
prepareRecipe() prepareRecipe()
brewCoffeeGrinds() steepTeaBag() brew() brew()
addSugarAndMilk() addLemon() addCondiments() addCondiments()

8
The New Java Classes….
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew(); Because Coffee and Tea handle
pourInCup(); these in different ways, they
addCondiments(); are going to have to be declared
} as abstract. Let the subclasses
worry about that stuff!
abstract void brew();
abstract void addCondiments();

void boilWater() {
System.out.println("Boiling water");
}
void pourInCup() {
System.out.println("Pouring into cup");
}
}
9
The New Java Classes…
public class Tea extends CaffeineBeverage {
public void brew() {
System.out.println("Steeping the tea");
}
public void addCondiments() {
System.out.println("Adding Lemon");
}
}

public class Coffee extends CaffeineBeverage {


public void brew() {
System.out.println("Dripping Coffee through filter");
}
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}
}

10
What have we done?
 We have recognized that the two recipes are essentially the
same, although some of the steps require different
implementations.
 So we’ve generalized the recipe and placed it in the base class.
 We’ve made it so that some of the steps in the recipe rely on the
subclass implementations.

Starbuzz Coffee Recipe Starbuzz Tea Recipe


(1) Boil some water • Boil some water
(2) Brew coffee in boiling water • Steep tea in boiling water
(3) Pour coffee in cup • Pour tea in cup
(4) Add sugar and milk • Add lemon

Caffeine Beverage
1. Boil some water
2. Brew
3. Pour beverage in a cup
4. Add condiments

Essentially - we have implemented the Template Method Pattern!


11
The New Java Classes… prepareRecipe() is the
public abstract template method here. Why?
class CaffeineBeverage { Because:
final void prepareRecipe(){ (1) it is a method
Some methods are (2) it serves as a template for
boilWater();
handled by this class an algorithm. In this case an
brew(); algorithm for making
pourInCup(); ….and some are caffeinated beverages.
handled by the
addCondiments(); subclass. In the template, each step of
} the algorithm is represented
by a method.
abstract void brew();
Methods that need
abstract void addCondiments(); to be supplied by
the subclass are
void boilWater() { // implementation } declared abstract.
void pourInCup() { // implementation }
}

The Template Method defines the steps of an algorithm and allows subclasses
to provide the implementation of one or more steps.
12
The Template Method Defined
The Template Method Pattern defines the skeleton of an algorithm in a
method, deferring some steps to subclasses. Template method lets
subclasses redefine certain steps of an algorithm without changing the
algorithm’s structure.
The template method makes use of the
primitiveOperations to implement an
The Abstract algorithm. It is decoupled from the actual
Class contains the AbstractClass implementations of these operations.
template method.
primitiveOperation1();
templateMethod()
primitiveOperation2();
….and abstract primitiveOperation1()
versions of the primitiveOperation2()
operations used in the
template method.

There may be many implements the abstract


ConcreteClass operations, which are called
ConcreteClasses each
implementing the full set when the templateMethod()
of operations required by
primitiveOperation1() needs them.
primitiveOperation2()
the template method.
13
Hooked on the Template Method
 A hook is a method that is declared in the abstract class,
but only given an empty or default implementation.
 Gives the subclasses the ability to “hook into” the algorithm at
various points, if they wish; they can ignore the hook as well.
public abstract class CaffeineBeverageWithHook {
void prepareRecipe() {
boilWater(); We’ve added a little conditional
brew(); statement that bases its success on
pourInCup(); a concrete method,
if (customerWantsCondiments()){ customerWantsCondiments(). If the
addCondiments(); customer WANTS condiments, only
} then do we call addCondiments()
}
abstract void brew();
abstract void addCondiments();
void boilWater() { // implementation } This is a hook, because a
void pourInCup() { // implementation } subclass can override this
boolean customerWantsCondiments() { method but doesn’t have to.
return true;
}
}
If subclasses want to use the hook they simply override it!
14
Using hook: Override it in our subclass
public class CoffeeWithHook extends CaffeineBeverageWithHook {
public void brew() {
System.out.println("Dripping Coffee through filter");
}
public void addCondiments() {
System.out.println("Adding Sugar and Milk");
}

public boolean customerWantsCondiments() {


String answer = getUserInput();
if (answer.toLowerCase().startsWith("y")) { return true; }
else { return false; }
}
private String getUserInput() {
String answer = null;
System.out.print("Would you like milk and sugar (y/n)? ");
BufferedReader in = new BufferedReader(
new InputStreamReader(System.in));
try { answer = in.readLine(); }
catch (IOException ioe) {
System.err.println("IO error trying to read your answer");
}
if (answer == null) { return "no"; }
return answer;
}
} 15
DP: The Hollywood Principle
Don’t call us, we’ll call you!
 The Hollywood Principle gives us a way to prevent “dependency rot”
 Dependency rot happens when you have high-level components depending
on low-level components depending on high level components depending
on sideways components depending on low level components and so on….
 With the Hollywood principle
 We allow low level components to hook themselves into a system
 But high level components determine when they are needed and how.
 High level components give the low-level components a “don’t call us, we’ll
call you” treatment.

But high-level components


control when and how.
High Level Component
Low-level components
can participate in the Low Level Low Level A low-level component
computation. Component Component never calls a high-level
component directly.
16
The Hollywood Principle and the Template
Method
Clients of beverages will depend
CaffeineBeverage is our CaffeineBeverage
on the CaffeineBeverage
high-level component. It has
abstraction rather than a
control over the algorithm prepareRecipe() concrete Tea or Coffee, which
for the recipe, and calls on boilWater() reduces dependencies in the
the subclasses only when brew() overall system.
they are needed for an pourInCup()
implementation of a method. addCondiments()

Coffee Tea

brew() brew()
addCondiments() addCondiments()

The subclasses are used simply to Tea and Coffee never call the
provide implementation details. abstract class directly without
being “called” first.

What other patterns make use of the Hollywood Principle? 17


Template Methods in the Wild
 Template method is a very common pattern and you’re
going to find lots in the wild!
 Some examples:
 Sorting with Template Method
 Swinging with Frames

18
Sorting with Template Method
 Arrays - common operation - sort them!
 Designers of Java Arrays provide a handy template method for sorting.

public static void sort(Object[] a) {


The mergeSort() method contains the
Object aux[] = (Object[])a.clone() ;
sort algorithm, and relies on an
mergeSort(aux, a, 0, a.length, 0); implementation of the compareTo()
} method to complete the algorithm.

private static void mergeSort(Object[] src, Think of this as the


Object[] dest, int low, int high, int off) { template method
for (int i = low; i < high; i++ ) {
for (int j = i; j > low &&
((Comparable)dest[j-1].compareTo(
(Comparable)dest[j]) > 0; j--) {
swap(dest, j, j-1);
} compareTo() is the method we
} need to implement to "fill out" the
return; This is a concrete method already template method.
} defined in the Arrays class.

19
Sorting some Ducks…
 Assume that you have an array of ducks to sort. How would
you do it?
 Use the sort() template method in the Array to do the sort
 Need to implement the compareTo() method -- to tell the sort()
how to compare ducks.
 Any issues here?

In the Template method we typically would subclass something. An array


doesn’t subclass anything.
Reason: The designers of sort() wanted it to be useful across all arrays, so
they had to make sort() a static method that could be used from anywhere.
One more detail - because we are not using subclassing, the sort() method
needs to know that you have implemented the compareTo() method.
To handle this there is the Comparable interface that your class needs to
implement. It has just one method – compareTo() .

20
Comparing Ducks and Ducks
public class Duck implements Comparable { public class DuckSortTestDrive {
String name; public static void main(String[] args){
int weight; Duck[] ducks = {
new Duck ("Daffy", 8),
public Duck(String name, int weight) {
new Duck ("Dewey", 2),
this.name = name;
this.weight = weight; new Duck ("Howard", 7),
} new Duck ("Louie", 2),
public String toString() { new Duck ("Donald", 10),
return name + “ weighs “ + weight; new Duck ("Huey", 2) };
} System.out.println("Before sorting");
display(ducks);
public int compareTo( Object object ) {
Duck otherDuck = (Duck) object; Arrays.sort(ducks);
if (this.weight < otherDuck.weight) { System.out.println("\n After Sorting");
return -1; display(ducks);
} else }
if (this.weight==otherDuck.weight) {
return 0;
} else { //this.weight > otherDuck.weight public static void display(Duck[] ducks) {
return 1; for (int j=0; j < ducks.length; j++)
} System.out.println(ducks[j]);
} }
} }
21
Is this really a Template Method Pattern?
 The pattern calls for implementing an algorithm, and
letting subclasses supply the implementation of the steps.
 Array.sort() is doing just that!
 Patterns in real life are often adaptations of the book
patterns
 Designers of the Arrays.sort() method had some
constraints:
 In general you can’t subclass Java Array and they wanted sort to be
useful for all arrays
 For Array sort() implementation:
 static method was defined
 Comparison was deferred to the items being sorted.
 So yes this is a Template Method!

22
Swingin’ with Frames
 JFrame - most basic Swing container and inherits a
paint() method.
 Default behavior of paint() method - does nothing
because it is a hook.
 By overriding the paint() method, you can insert
yourself into JFrame’s algorithm for displaying its
area of screen and have your own graphic output
incorporated into the JFrame.

 Next up -- a simple example using JFrame to override


the paint() method.

23
Simple JFrame Example
We’re extending JFrame, which
contains a method update() that
public class MyFrame extends JFrame { controls the algorithm for updating the
screen. We can hook into that algorithm
public MyFrame(String title) { by overriding the paint() method.
super(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

this.setSize(300,300); Don’t look behind the curtain,


this.setVisible(true); just some initialization here….
}

public void paint(Graphics graphics) { JFrame’s update algorithm calls


super.paint(graphics); paint(). By default paint() does
String msg = "I rule!!"; nothing…it’s a hook. We are
graphics.drawString(msg, 100, 100); 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");
}
}

24
Applets example
 Applets provide numerous hooks!
public class MyApplet extends Applet { allows the applet to do whatever it wants to
String message; initialize the applet the first time.
public void init() {
message = "Hello World, I'm alive!"; repaint() is a concrete method in the Applet class
repaint(); that lets upper-level components know that the
} applet needs to be redrawn.
public void start() {
message = "Now I'm starting up..."; allows the applet to do something when the applet
repaint(); is just about to be displayed on the web page.
}
public void stop() { If the user goes to another page, the stop
message = "Oh, now I'm being stopped...";hook is used and the applet can do whatever
repaint(); it needs to do to stop its actions.
}
public void destroy() { used when the applet is going to be destroyed, say,
message = "Goodbye, cruel world"; when the browser pane is closed. We could try and
repaint(); display something here…but what’s the point?
}
public void paint(Graphics g) { Well looky here! Applet also makes
g.drawString(message, 5, 15); use of the paint() method as a hook.
}
}
Concrete applets make extensive use of hooks to supply their own
behaviors. Because these methods are implemented as hooks, the
applet isn’t required to implement them.
25
Summary (1/2)
 A “template method” defines the steps of an algorithm,
deferring to subclasses for the implementation of those
steps.
 The Template Method Pattern gives us an important
technique for code reuse.
 The template method’s abstract class may define concrete
methods, abstract methods and hooks.
 Abstract methods are implemented by subclasses.
 Hooks are methods that do nothing or default behavior in
the abstract class, but may be overridden in the subclasses.
 To prevent the subclasses from changing the algorithm in
the template method, declare the template method as
final.

26
Summary (2/2)
 The Hollywood Principle guides us to put decision
making in high level modules that can decide how and
when to call the low-level modules.
 You’ll see lots of uses of the Template Method Pattern
in real world code, but don’t expect it all (like any
pattern) to be designed “by the book”.
 The Factory Method is a specialization of the Template
Method!

27
Well-Managed Collections!

1
Breaking news…..
 The Objectville Diner and Pancake House have merged!
Menus must be merged and have their separate identities!
Owners agree on the implementation of the MenuItems.

2
Check out the Menu Items

3
Check out the Menu Items
public class MenuItem {
String name;
String description;
boolean vegetarian;
double price;

public MenuItem(String name,


String description,
boolean vegetarian,
double price) {
// code here
}
// set of getter methods to get access to the fields.

4
Menu Implementations - Pancake House
public class PancakeHouseMenu {
ArrayList menuItems;
public PancakeHouseMenu() { Uses an ArrayList, so the
menuItems = new ArrayList(); menu can be easily expanded.

addItem("Regular Pancake Breakfast",


"Pancakes with fried eggs, sausage", false, 2.99);
addItem("Blueberry pancakes",
"Pancakes made with fresh blueberries", true, 3.49);
// other items
}
public void addItem(String name, String description,
boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description,
vegetarian, price);
menuItems.add(menuItem);
} To add a menuItem -
public ArrayList getMenuItems() { create a MenuItem object,
return menuItems;
add it to the arrayList
}
// other methods
}
5
Dinner Menu Implementations
public class DinerMenu implements Menu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems; Uses an array of menu item
public DinerMenu() {
menuItems = new MenuItem[MAX_ITEMS];
addItem("Vegetarian BLT",
"(Fakin') Bacon with lettuce & tomato on whole wheat",
true, 2.99);
// other menu items
}
public void addItem(String name, String description,
boolean vegetarian, double price) {
MenuItem menuItem =
new MenuItem(name, description, vegetarian, price);
if (numberOfItems >= MAX_ITEMS) {
System.err.println("Sorry, menu is full!");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems = numberOfItems + 1;
}
}
public MenuItem[] getMenuItems() {
return menuItems;
}
6
What’s the problem with having two
different menu representations?

7
The methods look the
same, but return
Implementing the Waitress different types --
1. To print all the items on each menu: ArrayList versus Array

PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();


ArrayList breakfastItems = pancakeHouseMenu.getMenuItems();
DinerMenu dinerMenu = new DinerMenu();
MenuItem[] lunchItems = dinerMenu.getMenuItems();

2. Print the items from the PancakeHouseMenu and the


DinerHouseMenu -- need to loop over the ArrayList and Array
respectively.
for (int j = 0; j < breakfastItems.size(); j++){
MenuItem menuItem = (MenuItem)breakfastItems.get(j);
System.out.println(menuItem.getName());
// print out the description, vegetarian, and price
}
for (int j = 0; j < lunchItems.length; j++) {
MenuItem menuItem = lunchItems[j]; }

3. Implementing the other methods is a variation on this theme. If


another restaurant is added in, we would need three loops!
8
What now?
 Implementations can not be modified
 Requires rewriting a lot of code in each respective menu
 Need: same interface for menus
 getMenuItems() need to return a common object type
 How do we do that?

9
What now?
 One of the key principles is : encapsulate what varies.
What varies here?
 Iteration caused by different collections of objects
returned from the menus.
 Can we encapsulate this?
1. To iterate through the breakfast items we use size()
and get() methods on the Arraylist.
2. To iterate through the lunch items we use the Array
length field and the array subscript notation on
MenuItem Array.

10
Simple Iterator
 What if we create an object, an Iterator, that
encapsulates how we iterate through a collection of
objects.
Iterator iterator = breakfastMenu.createIterator();
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
}
 Similarly,
Iterator iterator = dinerMenu.createIterator();
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem)iterator.next();
}

11
Meet the Iterator Pattern
 The Iterator Design Pattern relies on an interface
called the Iterator interface.
A possible Iterator
interface
<<Interface>>
Iterator
public interface Iterator {
hasNext() boolean hasNext();
next() Object next();
}

PancakeHouseMenuIterator DinerMenuIterator

hasNext() hasNext()
next() next()

12
Using the Iterator for the Diner Menu
public class DinerMenuIterator implements Iterator {
MenuItem[] items; position maintains the current position
int position = 0; of the iteration over the array.

public DinerMenuIterator(MenuItem[] items) {


this.items = items;
} The constructor takes the array of
menu items we are going to iterate over.
public Object next() {
MenuItem menuItem = items[position];
position = position + 1;
The next() method returns the next item
return menuItem;
in the array and increments the position.
}

public boolean hasNext() {


if (position >= items.length || items[position] == null)
{
return false; The hasNext() method checks to see if
} else { return true; } we’ve seen all the elements of the array
}
}
13
Reworking the Diner Menu with Iterator
public class DinerMenu {
static final int MAX_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
We’re not going to need the
// constructor here getMenuItems() method anymore and
in fact we don’t want it because it
// addItem here exposes our internal implementation!

public MenuItem[] getMenuItems() {


return menuItems; creates a DinerMenuIterator
} from the menuItems array and
returns it to the client.
public Iterator createIterator() {
return new DinerMenuIterator(menuItems);
}
// other menu methods here
}
We’re returning the Iterator interface.
The client doesn’t need to know how the menuItems are maintained in
the DinerMenu, nor how the DinerMenuIterator is implemented. It
just needs to use the iterators to step through the items in the menu.
14
Fixing up the Waitress Code
public class Waitress { Waitress takes the two
PancakeHouseMenu pancakeHouseMenu; objects as before
DinerMenu dinerMenu;
public Waitress(PancakeHouseMenu pancakeHouseMenu,
DinerMenu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
} The printMenu() creates two
iterators one for each menu
public void printMenu() {
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("\nLunch");
printMenu(dinerIterator);
// similar set of statements for Breakfast menu
}

public void printMenu(Iterator iterator) {


while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
// print it out
}
} Back to one loop! Here is where the printing occurs.
}
15
What have we done?
 The Menus are not well  The Menu implementations are now
encapsulated; we can see the Diner encapsulated. The Waitress has no
is using an ArrayList and the idea how the Menus hold their
Pancake House an Array. collection of menu items.
 We need two loops to iterate  All we need is a loop that
through the MenuItems. polymorphically handles any
collection of items as long as it
implements the iterator.
 The Waitress is bound to concrete  The Waitress now uses an interface
classes (MenuItem[] and (Iterator).
ArrayList)
 The Waitress is bound to two  The Menu interfaces are now exactly
concrete Menu classes, despite their the same and uh, oh, we still don’t
interfaces being almost identical. have a common interface, which
means the Waitress is still bound
to two concrete Menu classes.

16
Bird’s Eye View of Current Design
The waitress is still bound to The Iterator allows the Waitress to be decoupled from the actual
two concrete Menu classes implementation of the concrete classes. She does not need to
Solution: define a common know if a Menu is implemented with an Array or ArrayList! All she
interface for two classes cares is that she can get an iterator to do her iterating.

<<Interface>>
PancakeHouseMenu Waitress Iterator
<<use>>
menuItems
printMenu() hasNext()
createIterator() next()

DinerMenu
menuItems

createIterator()
PancakeHouseMenuIterator DinerMenuIterator
<<create>>
hasNext() hasNext()
next() next()
<<create>>
Note that the iterator gives us a way to step through the elements of an aggregate without having
the aggregate clutter its own interface with a bunch of methods to support traversal of its
elements. It also allows the implementation of the iterator to live outside the aggregate --- in other
words, we ‘ve encapsulated the iteration.
17
The Iterator Pattern Defined
The Iterator Pattern provides a way to access the elements
of an aggregate object sequentially without exposing its
underlying implementation.
<<Interface>>
<<Interface>>
Iterator
Aggregate Client
hasNext()
createIterator() next()

ConcreteIterator
ConcreteAggregate <<create>>
hasNext()
createIterator()
Next()

The Iterator places the task of traversal on the iterator object, not
on the aggregate, which simplifies the aggregate interface and
implementation, and places the responsibility where it should be.
18
DP: Single Responsibility
A class should have only one reason to change.
 Every responsibility of a class is an area of potential
change. More than one responsibility means more
than one area of change.

 This principle guides us to keep each class to a single


responsibility.

 We have studied the principle of single responsibility


at the module level. What is it?

19
20
The java.util.Iterator
 The java.util.Iterator interface supports the Iterator
pattern that we have discussed thus far.
 The Java Collections Framework – provides a set of
classes and interfaces, including ArrayList, Vector,
LinkedList, Stack and PriorityQueue.
 All of these classes implement the Collection
interface, and provide a method iterator() to return
an instance of the java.util.iterator to iterate over the
collection.

21
Using java.util.Iterator
The Waitress is decoupled from the implementation of the menus, so
now we can use an Iterator to iterate over any list of menu items
without having to know about how the list of items is implemented.
<<Interface>>
<<Interface>> java.util.Iterator
Waitress <<use>>
Menu
hasNext()
createIterator() printMenu() next()
remove()

PancakeHouseMenuIterator DinerMenuIterator
PancakeHouseMenu DinerMenu
menuItems menuItems hasNext() hasNext()
next() next()
createIterator() createIterator() remove() remove()
<<create>>
<<create>>

These now implement using the ArrayList iterator DinerMenu returns a


the Menu interface supplied by java.util. DinerMenuIterator from its
createIterator() method because
that’s the kind of iterator required to
iterate over its Array of menu items.
22
DinerMenuIterator implement java.util.Iterator
public class DinerMenuIterator implements Iterator {
MenuItem[] list;
int position = 0;
public Object next() { // the same of above }
public boolean hasNext() { // the same of above }
public void remove() {
if (position <= 0) {
throw new IllegalStateException(
"You can't remove an item until " +
"you've done at least one next()");
}
if (list[position - 1] != null) {
for (int i = position - 1;
i < (list.length - 1); i++) {
list[i] = list[i + 1];
}
list[list.length - 1] = null;
}
}
}
23
Iterator in Java 5
 Iterators and Collections in Java 5:
 Added support for iterating over Collections so that you don’t even
have to ask for an iterator!
 Includes a new form of for statement -- for/in
 Lets you iterate over a collection or an array without creating an
iterator explicitly.
ArrayList items = new ArrayList();
items.add(new MenuItem("Pancakes",
"delicious pancakes", true, 1.59);
items.add(new MenuItem("Waffles",
"yummy waffles", true, 1.99);
items.add(new MenuItem("Toast",
"perfect toast", true, 0.59);
for (MenuItem item : items) {
System.out.println("Breakfast item: " + item);
}
24
Is the Waitress ready for prime time?
public void printMenu(){
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
Iterator cafeIterator = cafeMenu.createIterator();

System.out.println("MENU\n-------\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
System.out.println("\nDINNER");
printMenu(cafeIterator);
}

void printMenu(Iterator iterator) {


// iterate over the collection and print
}

 Whats wrong with this?


 We have done a good job of decoupling the menu implementation
and extracting the iteration into an iterator. But we are still
handling the menus with separate, independent objects – we need a
way to manage them together.
 Ideas?
25
Packaging into an ArrayList
 We could package the menus up into an ArrayList and
then get its iterator to iterate through each Menu.
public class Waitress {
ArrayList menus;
public Waitress(ArrayList menus) {
this.menus = menus; We do loose the name of the
} menus in this implementation.
public void printMenu() {
Iterator menuIterator = menus.iterator();
while (menuIterator.hasNext()) {
Menu menu = (Menu) menuIterator.next();
printMenu(menu.createIterator());
}
}
void printMenu(Iterator iterator) {
// no code changes here
}
}
26
Just when we thought it was safe …
 The Diner wants to add a new dessert “submenu”
 What does that mean?
 We have to support not only multiple menus, but menus within
menus.
 Solutions: we could make the Dessert menu an element of
the DinerMenu collection, but that won’t work as it is now
implemented.
 DessertMenu will need to be implemented as a collection
 We can’t actually assign a menu to a MenuItem array because the
types are different.

 Time for a change!

27
The Desired Menu Structure
All Menus
ArrayList
1 2 3 Coffee Menu

HashTable
Dinner Menu
Pancake Menu

2
1 2 3 4
ArrayList 3
Array
1 4

2
Dessert Menu
3

4
28
So what do we need?
 We need some kind of a tree shaped structure that will
accommodate menus, submenus, and menu items
 We need to make sure we maintain a way to traverse the
items in each menu that is at least as convenient as what
we are doing now with iterators
 We need to be able to traverse the items in a more flexible
manner.
 For instance, we might need to iterate over only the Diner’s dessert
menu, or we might need to iterate over the Diner’s entire menu,
including the dessert menu.

29
Possibilities
Menus and submenus sub-structure
naturally fit into a tree-like structure

All Menus

PancakeHouseMenu

Can accommodate DinerMenu


menus, submenus
and menuitems

DessertMenu

MenuItems

30
The Composite Pattern Defined
The Composite Pattern allows you to compose objects into
tree structures to represent whole-part hierarchies.
Composite lets clients treat individual objects and
composition of objects uniformly.

node 1. We can create arbitrarily


complex trees.
2. We can treat them as a
whole or as parts
3. Operations can be applied
to the whole or the part.

leaf

31
Composite Pattern Structure
defines an interface for all objects in the
The client uses the
composition: composite and leaf nodes.
Component interface to
manipulate the objects
in the composition. Component
may implement a
Client default behavior for
operation()
add(Component) add(), remove(),
remove(Component) getChild() and its
getChild(int) operations.

A leaf has
no children Composite
Leaf
children
for all g in children {
defines the behavior operation()
g.operation();
for the elements in operation()
}
the composition. add(Component)
remove(Component)
getChild(int)

The Composite’s role is to define the also implements the


behavior of the components having Leaf-related operations.
children and to store child components
32
Designing Menus with Composite
MenuComponent abstract class
represents the interface for
Waitress MenuComponent both MenuItem and Menu, and
provide default implementations
getName() for these methods.
The Waitress is going to use the getDescription()
MenuComponent interface to access getPrice()
both Menus and MenuItems. isVegetarian()
print()
Here are the methods for add(MenuComponent)
manipulating the components: remove(MenuComponent)
Menu and MenuItem. getChild(int)

MenuItem overrides the


methods that make sense,
and uses the default MenuItem Menu
implementations menuComponents
overrides the
(Unsupported Exception, for getName()
methods that make
example) in MenuComponent getDescription() getName()
sense, like a way to
for those that don’t make getPrice() getDescription()
add and remove menu
sense (like add()) isVegetarian() print()
print() add(MenuComponent) items (and submenus!)
remove(MenuComponent) from the
Both MenuItem and Menu getChild(int) menuComponents.
override the print() method.
33
Implementing the Menu Component

34
Implementing the Menu Item
public class MenuItem extends MenuComponent {
String name;
String description;
boolean vegetarian;
double price;

public MenuItem(String name, String description,


boolean vegetarian, double price) {
this.name = name;
this.description = description;
this.vegetarian = vegetarian;
this.price = price;
}

//...

public void print() {


System.out.print(" " + getName());
if (isVegetarian()) {
System.out.print("(v)");
}
System.out.println(", " + getPrice());
System.out.println(" -- " + getDescription());
}
}
35
Implementing the Menu Composite
public class Menu extends MenuComponent {
ArrayList menuComponents = new ArrayList();
String name;
String description;
public Menu(String name, String description) {
this.name = name;
this.description = description;
}
public void add(MenuComponent menuComponent) {
menuComponents.add(menuComponent);
}
public void remove(MenuComponent menuComponent) {
menuComponents.remove(menuComponent);
}
public MenuComponent getChild(int i) {
return (MenuComponent) menuComponents.get(i);
}
public void print() {
System.out.print("\n" + getName());
System.out.println(", " + getDescription());
System.out.println("---------------------");
Iterator iterator = menuComponents.iterator();
while (iterator.hasNext()) {
MenuComponent component = (MenuComponent) iterator.next();
component.print();
}
}
} 36
An Observation - Violating SRP?
 First we say: One Class, One Responsibility.
 Composite is a pattern with two responsibilities in one
class: manages a hierarchy and it performs operations
related to MenuItems.
 In the Composite pattern we trade the Single Responsibility
design principle for transparency.
 The client can treat both composites and leaf nodes uniformly
 We lose: safety because the client may try to do something
inappropriate or meaningless.
 We could take the design in the other direction and separate out the
responsibilities into interfaces. This could make the design safe.
 We would loose transparency in this case and our code would have
to use conditionals and the instanceOf operator.

37
Flashback to the Iterator – A Composite Iterator
 To implement a Composite Iterator we add the
createIterator() method in every component.
 We add a createIterator() method to the abstract
MenuComponent. means that calling createIterator() on a
composite should apply to all children of the composite.
 Implementations in Menu and MenuItem:

public class Menu extends MenuComponent {


// other code does not change
public Iterator createIterator() {
return new CompositeIterator(menuComponents.iterator());
}
CompositeIterator knows how
}
to iterate over any composite.
public class MenuItem extends MenuComponent {
// other code does not change
public Iterator createIterator() {
return new NullIterator();
} NullIterator coming up….
}
38
The Composite Iterator - A Serious Iterator
public class CompositeIterator implements Iterator {
Stack stack = new Stack(); implementing the
public CompositeIterator(Iterator iterator) java.util.Iterator
{ interface.
stack.push(iterator);
} The iterator of the top level composite
we’re going to iterate over is passed in.
public Object next() { We throw that in a stack data structure.
if (hasNext()) {
make sure there is
one by calling
Iterator iterator = (Iterator) stack.peek(); hasNext()
MenuComponent component =
(MenuComponent) iterator.next(); If there is a next element,
if (component instanceof Menu) { we get the current iterator
stack.push(component.createIterator()); off the stack and get its
} next element.
return component; If that element is a menu, we have another
} else { return null; } composite that needs to be included in the
} iteration, so we throw it on the stack. In
either case, we return the component.
// continue
39
The Composite Iterator (con't)
To see if there is a next
public boolean hasNext() { element, we check to see
if (stack.empty()) { return false; } if the stack is empty;
else {
Iterator iterator = (Iterator) stack.peek();
if (!iterator.hasNext()) {
stack.pop();
return hasNext(); Otherwise, we get the iterator off the
} else { return true; } top of the stack and see if it has a next
} element. If it doesnot we pop it off the
} stack and call hasNext() recursively.

public void remove() {


throw new UnsupportedOperationException();
}
}
We are not supporting remove, just
traversal.

40
The Null Iterator
 A MenuItem has nothing to iterate over. So how do we
handle the createIterator() implementation?
 Choice 1: return null
 We could return null, and have conditional code in the client to
check if a null was returned or not.
 Choice 2:
 Return an iterator that always returns a false when hasNext() is
called. --- create an iterator that is a no-op.
public class NullIterator implements Iterator {
public Object next() {
return null;
}
public boolean hasNext() {
return false;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
41
Give me the vegetarian menu…
public class Waitress {
MenuComponent allMenus;
public Waitress(MenuComponent allMenus) {
this.allMenus = allMenus;
} The printVegetarianMenu() method
public void printMenu() { takes the allMenu’s composite and
allMenus.print(); gets its iterator. This will be our
} CompositeIterator.
public void printVegetarianMenu() {
Iterator iterator = allMenus.createIterator();
System.out.println("\nVEGETARIAN MENU\n----");
while (iterator.hasNext()) {
MenuComponent menuComponent =
(MenuComponent)iterator.next();
try { print() is only called on MenuItems,
if (menuComponent.isVegetarian()) { never on composites.
menuComponent.print(); Can you see why?
}
} catch (UnsupportedOperationException e) {}
}
} We implemented isVegetarian() on the Menus to always
} throw an exception. If that happens we catch the
exception, but continue with the iteration….

42
Exceptions and Program Logic….
 In general, using exceptions to implement program logic is a big no,
no!
 Yet that’s exactly what we are doing with the isVegetarian() method.
 We could have checked the runtime type of the Menu component with
instanceOf to make sure it’s a MenuItem before making the call to
isVegetarian(). But in the process we would lose transparency.
 We could also change isVegetarian() in the Menus to return a
false. This provides a simple solution and we keep our transparency.
 We choose to go for clarity - we want to communicate that for the
Menus this really is an unsupported operation. It also allows for
someone to come along and implement a reasonable
isVegetarian() method for Menu and have it work with existing
code.

43
Other Composite Pattern Examples
 File System
 Graphic hierarchy
 Arithmetic Expression Tree
 List Structure
 Tree Structure

44
File System
FileSystemElement
 File và folder là các
name : String
thành phần của một
hệ thống quản lý tập getName()
print()
tin. getSize()
 File biểu diễn dữ liệu countFile()
cần lưu trữ.
 Folder là ngăn chứa
các tập tin. Trong mỗi
File Folder
folder có thể chứa các
size : int children : List<FileSystemElement>
folder con khác.
print() addElement(e : FileSystemElement)
getSize() removeElement(e : FileSystemElement)
countFile() print()
getSize()
countFile()

45
Graphic hierarchy

46
List Structure
<<Interface>>
IList

+ getFirst()
+ getRest()

EmptyList NEList
first : Object
rest : IList

getFirst() : Object
getRest() : IList

47
Arithmetic Expression hierarchy

48
Summary (1/2)
 An iterator allow access to an aggregate’s elements without
exposing its internal structure.
 An iterator takes the job of iterating over an aggregate and
encapsulates it in another object.
 When using an iterator, we relieve the aggregate of the
responsibility of supporting operations for traversing its
data.
 An iterator provides a common interface for traversing the
items of an aggregate, allowing us to use polymorphism
when writing code that makes use of the items of the
aggregate.
 We should strive to assign only one responsibility to each
class.

49
Summary (2/2)
 The Composite Pattern provides a structure to hold
both the individual objects and composites.
 The Composite Pattern allows clients to treat
composites and individual objects uniformly.
 A Component is any object in a composite structure.
Components may be other composites or leaf nodes.
 There are many design tradeoffs in implementing the
Composite. You need to balance transparency and
safety with your needs.

50

You might also like