1 Strategy Merged
1 Strategy Merged
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
2
A First Design for the Duck Simulator Game
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!
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.
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.
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()
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
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
+ 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
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!!");
}
}
+ performFly()
+ performQuack()
+ swim() FlyWithWings FlyNoWay FlyRocketPower
+ display() + fly() + fly() + fly()
+ setFlyBehavior(f : FlyBehavior)
+ setQuackBehavior(q : QuackBehavior)
<<Interface>>
QuackBehavior
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.
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
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.
Weather data
object
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.
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.
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();
}
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
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.
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.
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.
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
+ 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.
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.
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.
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.
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
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.
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
Decaf Expresso
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;
}
}
18
Coding Condiments
public class Mocha extends CondimentDecorator {
Beverage beverage;
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());
}
}
20
Real World Decorators
The java.io package uses the Decorator pattern!
Heres the abstract component InputStream
FilterInputStream is
an abstract decorator
PushbackInputStream DataInputStream
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));
}
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);
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 ( );
}
4
Identifying aspects that Vary
Order pizza in a pizza store in cutting edge
Objectville!
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!
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
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!!
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
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
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.
}
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
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.
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
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
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
30
DIP explained
Depend upon abstractions.
Do not depend upon
concrete classes.
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!
33
Building the Ingredient Factory
Ingredient factory: creates each ingredient in the
ingredient family (but does not handle regional differences
yet!)
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
<<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;
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();
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
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.
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)
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!
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;
7
Singleton Pattern Defined
The Singleton Pattern ensures a class has only one
instance, and provides a global point of access to it.
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();
12
What happened? Value of
Thread 1 Thread 2 uniqueC
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() {}
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 Vendor
Adapter
Existing Class
System
Your Vendor
Adapter
Existing Class
System
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
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
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();
}
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);
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.
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();
}
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();
} }
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");
}
}
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.
Caffeine Beverage
1. Boil some water
2. Brew
3. Pour beverage in a cup
4. Add condiments
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.
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.
18
Sorting with Template Method
Arrays - common operation - sort them!
Designers of Java Arrays provide a handy template method for sorting.
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?
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.
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);
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;
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.
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
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.
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.
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>>
System.out.println("MENU\n-------\nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
System.out.println("\nDINNER");
printMenu(cafeIterator);
}
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
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.
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)
34
Implementing the Menu Item
public class MenuItem extends MenuComponent {
String name;
String description;
boolean vegetarian;
double price;
//...
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:
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