0% found this document useful (0 votes)
81 views

WJ20228 OOP10 DesignPatterns

This document discusses design patterns in object-oriented programming. It introduces design patterns, explaining that they were first identified by Christopher Alexander for architecture and then applied to software design by the "Gang of Four" book. Design patterns provide reusable solutions to common programming problems, improving code quality, reuse, and maintainability. The document reviews key aspects of design patterns like their goals, examples, and advantages of using them.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
81 views

WJ20228 OOP10 DesignPatterns

This document discusses design patterns in object-oriented programming. It introduces design patterns, explaining that they were first identified by Christopher Alexander for architecture and then applied to software design by the "Gang of Four" book. Design patterns provide reusable solutions to common programming problems, improving code quality, reuse, and maintainability. The document reviews key aspects of design patterns like their goals, examples, and advantages of using them.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 157

Design Patterns

Object-Oriented Programming

Design Patterns

Object-Oriented Programming 1
Design Patterns Goals

▪ .Introduce the concept of design patterns.


• Explain how it arose from the field of architecture and anthropology.

▪ Discuss why design patterns are important and what advantages they provide.

▪ Present examples of design patterns.

Object-Oriented Programming 2
Design Patterns Design Patterns are Everywhere

▪ In 1995, a book was published by the “Gang of Four” called Design Patterns.
• It applied the concept of patterns (discussed next) to software design and described 23 of them.
- The authors did not invent these patterns.
- Instead, they included patterns they found in at least 3 “real” software systems.

▪ Since that time lots of Design Patterns books have been published.
• And more patterns have been cataloged.

▪ Unfortunately, many people feel like they should become experts in object-oriented
analysis and design before they learn about patterns.
• The book takes a different stance: learning about design patterns will help you become an
expert in object-oriented analysis and design.

Object-Oriented Programming 3
Design Patterns Christopher Alexander (I)

▪ Design patterns in software design traces its intellectual roots to work performed in the
1970s by an architect named Christopher Alexander.
• His 1979 book called “The Timeless Way of Building” that asks the question “Is quality
objective?”.
- In particular, “What makes us know when an architectural design is good? Is there an objective basis for
such a judgement?”.
• His answer was “yes” that it was possible to objectively define “high quality” or “beautiful”
buildings.
▪ He studied the problem of identifying what makes a good architectural design by
observing all sorts of built structures.
• Buildings, towns, streets, homes, community centers, etc.
▪ When he found an example of a high quality design, he would compare that object to
other objects of high quality and look for commonalties.
• Especially if both objects were used to solve the same type of problem.

Object-Oriented Programming 4
Design Patterns Christopher Alexander (II)

▪ By studying high quality structures that solve similar problems, he could discover
similarities between the designs and these similarities where what he called patterns.
• “Each pattern describes a problem which occurs over and over again in our environment and
then describes the core of the solution to that problem, in such a way that you can use this
solution a million times over, without ever doing it the same way twice”.
• The pattern provides an approach that can be used to achieve a high quality solution to its
problem.

Object-Oriented Programming 5
Design Patterns Four Elements of a Pattern

▪ Alexander identified four elements to describe a pattern.


• The name of the pattern.
• The purpose of the pattern: what problem it solves.
• How to solve the problem.
• The constraints we have to consider in our solution.
▪ He also felt that multiple patterns applied together can help to solve complex
architectural problems.

Object-Oriented Programming 6
Design Patterns Design Patterns and Software

▪ Work on design patterns got started when people asked:


• Are there problems in software that occur all the time that can be solved in somewhat the same manner?
• Was it possible to design software in terms of patterns?
▪ Many people felt the answer to these questions was “yes” and this initial work influenced
the creation of the Design Patterns book by the Gang of Four.
• It catalogued 23 patterns: successful solutions to common problems that occur in software design
▪ Design patterns, then, assert that the quality of software systems can be measured
objectively.
• What is present in a good quality design (X’s) that is not present in a poor quality design?
• What is present in a poor quality design (Y’s) that is not present in a good quality design?
▪ We would then want to maximize the X’s while minimizing the Y’s in our own designs.

Object-Oriented Programming 7
Design Patterns Key Features of a Pattern

▪ “Descriptions of communicating objects and classes that are customized to solve a general design
problem in a particular context.”
[Gamma, Helm, Johnson, Vlissides 1995]

▪ Name
▪ Intent: The purpose of the pattern.
▪ Problem: What problem does it solve?
▪ Solution: The approach to take to solve the problem.
▪ Participants: The entities involved in the pattern.
▪ Consequences: The effect the pattern has on your system.
▪ Structure: Class Diagram.
▪ Implementation: Example ways to implement the pattern.
▪ Sample code
▪ Related patterns

Object-Oriented Programming 8
Design Patterns Why Study Design Patterns?

▪ Patterns let us
• reuse solutions that have worked in the past; why waste time reinventing the wheel?
• have a shared vocabulary around software design.
- They allow you to tell a fellow software engineer “I used a Strategy pattern here to allow the algorithm
used to compute this calculation to be customizable”.
- You don’t have to waste time explaining what you mean since you both know the Strategy pattern.

▪ Design patterns provide you not with code reuse but with experience reuse.
• Knowing concepts such as abstraction, inheritance and polymorphism will NOT make you a good designer,
unless you use those concepts to create flexible designs that are maintainable and that can cope with
change.

▪ Design patterns can show you how to apply those concepts to achieve those goals.

Object-Oriented Programming 9
Design Patterns A Sense of Perspective

▪ Design Patterns give you a higher-level perspective on:


• the problems that come up in object-oriented analysis and design work;
• the process of design itself;
• the use of object orientation to solve problems.
▪ You’ll be able to think more abstractly and not get bogged down in implementation details
too early in the process.

Object-Oriented Programming 10
Design Patterns Other Advantages

▪ Improved Motivation of Individual Learning in Team Environments.


• Junior developers see that the design patterns discussed by more senior developers are valuable and are
motivated to learn them.
▪ Improved maintainability.
• Many design patterns make systems easy to extend, leading to increased maintainability.
▪ Design patterns lead to a deeper understanding of core OO principles.
▪ They reinforce useful design heuristics such as:
• code to an interface
• favor delegation over inheritance
• find what varies and encapsulate it
▪ Since they favor delegation, they help you avoid the creation of large inheritance
hierarchies, reducing complexity.

Object-Oriented Programming 11
Design Patterns Original Catalogue of Patterns

Purpose
Creational Structural Behavioral
Abstract Factory Adapter Bridge Chain of Responsibility
Builder Composite Command
Factory Method Decorator Interpreter
Prototype Façade Iterator
Singleton Flyweight Mediator
Proxy Memento
Observer
State
Strategy
Template Method
Visitor

Object-Oriented Programming 12
Design Patterns Original Catalogue of Patterns

Purpose
Creational Structural Behavioral
Abstract Factory Adapter Chain of Responsibility
Builder Bridge Command
Factory Method Composite Interpreter
Prototype Decorator Iterator
Singleton Façade Mediator
Flyweight Memento
Proxy Observer
State
Strategy
Template Method
Visitor

▪ Patterns We will be talking about in detail; you should read about the others in the book
or online.

Object-Oriented Programming 13
Design Patterns Design Pattern by Example

▪ SimUDuck: a “duck pond simulator” that can show a wide variety of duck species
swimming and quacking
• Initial State

▪ But a request has arrived to allow ducks to also fly. (We need to stay ahead of the
competition!)

Object-Oriented Programming 14
Design Pattern by Example Easy

Code Reuse via Inheritance


Add fly() to Duck; all ducks can now fly

Object-Oriented Programming 15
Design Pattern by Example Whoops!

Rubber ducks do not fly! They don’t


quack either, so we override quack()
to make them squeak

We could override fly() in


RubberDuck to make it do
nothing, but that’s less than
ideal, especially…

Object-Oriented Programming 16
Design Pattern by Example Double Whoops!

…when we might find


other Duck subclasses
that would have to do
the same thing!

What was supposed to be a good instance of reuse via


inheritance has turned into a maintenance headache!

Object-Oriented Programming 17
Design Pattern by Example What about an Interface?

Here we define two interfaces and


allow subclasses to implement the
interfaces they need.

What are the trade-offs?

Object-Oriented Programming 18
Design Pattern by Example Design Trade-offs

▪ With inheritance, we get


• Code reuse, only one fly() and quack() method vs. multiple (pro)
• Common behavior in root class, not so common after all (con)

▪ With interfaces, we get


• Specificity: only those subclasses that need a fly() method get it (pro)
• No code re-use: since interfaces only define signatures (con)

▪ Use of abstract base class over an interface? Could do it, but only in languages that
support multiple inheritance
• In this approach, you implement Flyable and Quackable as abstract base classes and then have Duck
subclasses use multiple inheritance

Object-Oriented Programming 19
Design Pattern by Example Design Principles to the Rescue!

▪ Encapsulate What Varies


• For this particular problem, the “what varies” is the behaviors between Duck subclasses
- We need to pull out behaviors that vary across the subclasses and put them in their own classes (i.e.,
encapsulate them)
• The result: fewer unintended consequences from code changes (such as when we added fly() to
Duck) and more flexible code

Object-Oriented Programming 20
Design Pattern by Example Basic Idea

▪ Take any behavior that varies across Duck subclasses and pull them out of Duck.
• Duck will no longer have fly() and quack() methods directly.
• Create two sets of classes, one that implements fly behaviors and one that implements quack
behaviors.
▪ Code to an Interface.
• We’ll make use of the “code to an interface” principle and make sure that each member of the
two sets implements a particular interface.
- For QuackBehavior, we’ll have Quack, Squeak, MuteQuack
- For FlyBehavior, we’ll have FlyWithWings, FlyNoWay, FlyWhenThrown, …
▪ Additional Benefits.
• Other classes can gain access to these behaviors and we can add additional behaviors without
impacting other classes.

Object-Oriented Programming 21
Design Pattern by Example “Code to Interface” Does NOT Imply Java Interface

▪ We are overloading the word “interface” when we say “code to an interface”


• We can implement “code to an interface” by defining a Java interface and then have various
classes implement that interface.
• Or, we can “code to a supertype” and instead define an abstract base class which classes can
access via inheritance.

▪ When we say “code to an interface” it implies that the object that is using the interface
will have a variable whose type is the supertype (whether it is an interface or an abstract
base class) and thus
• can point at any implementation of that supertype
• and is shielded from their specific class names
- A Duck will point to a fly behavior with a variable of type FlyBehavior NOT FlyWithWings; the code will
be more loosely coupled as a result.

Object-Oriented Programming 22
Design Pattern by Example Bringing it all Together: Delegation

▪ .To take advantage of these new behaviors, we must modify Duck to delegate its flying and
quacking behaviors to these other classes
• rather than implementing this behavior internally.

▪ We’ll add two attributes that store the desired behavior and we’ll rename fly() and
quack() to performFly() and performQuack()
• this last step is meant to address the issue of it not making sense for a DecoyDuck to have
methods like fly() and quack() directly as part of its interface.
- Instead, it inherits these methods and plugs-in CantFly and Silence behaviors to make sure that it does
the right things if those methods are invoked.

▪ This is an instance of the principle “Favor delegation over inheritance”.

Object-Oriented Programming 23
Design Pattern by Example New Class Diagram

<<interface>> <<interface>>
flyBehavior quackBehavior
FlyBehavior QuackBehavior
fly() quack()
Duck
flyBehavior
quackBehavior
swim()
display()
FlyWithWings FlyNoWay MuteQuack Quack Squeak
setFlyBehavior(FlyBehavior)
fly() fly() setQuackBehavior(QuackBehavior) quack() quack() quack()
performFly()
performQuack()

MallardDuck RedheadDuck RubberDuck DecoyDuck


display() display() display() display()

▪ FlyBehavior and QuackBehavior define a set of behaviors that provide behavior to Duck.
▪ Duck delegates to each set of behaviors and can switch among them dynamically, if needed.
▪ While each subclass now has a performFly() and performQuack() method, at least the user interface is
uniform and those methods can point to null behaviors when required.

Object-Oriented Programming 24
Design Pattern by Example FlyBehavior.java and QuackBehavior.java

FlyBehavior.java FlyWithWings.java

1 public interface FlyBehavior { 1 public class FlyWithWings implements FlyBehavior {


2 public void fly(); 2
3 public void fly() {
3 }
4 System.out.println("I'm flying!!");
5 }
6
7 }

FlyRocketPowered.java FlyNoWay.java
1 public class FlyRocketPowered implements FlyBehavior { 1 public class FlyNoWay implements FlyBehavior {
2 2
3 public void fly() { 3 public void fly() {
4 System.out.println("I'm flying with a rocket"); 4 System.out.println("I can't fly");
5 } 5 }
6 6
7 } 7 }

Object-Oriented Programming 25
Design Pattern by Example FlyBehavior.java and QuackBehavior.java

QuackBehavior.java Squeak.java

1 public interface QuackBehavior { 1 public class Squeak implements QuackBehavior {


2 public void quack(); 2
3 3 public void quack() {
}
4 System.out.println("Squeak");
5 }
6
7 }

Quack.java MuteQuack.java
1 public class Quack implements QuackBehavior { 1 public class MuteQuack implements QuackBehavior {
2 2
3 public void quack() { 3 public void quack() {
4 System.out.println("Quack"); 4 System.out.println("<< Silence >>");
5 } 5 }
6 6
7 } 7 }

Object-Oriented Programming 26
Design Pattern by Example Duck.java

Duck.java Duck.java (continue)


1 public abstract class Duck { 16 public void performFly() {
2 FlyBehavior flyBehavior; 17 flyBehavior.fly();
3 QuackBehavior quackBehavior; 18 }
4 19
5 public Duck() {} 20 public void performQuack() {
6 21 quackBehavior.quack();
7 public void setFlyBehavior(FlyBehavior fb) { 22 }
8 flyBehavior = fb; 23
9 } 24 public void swim() {
10 25 System.out.println("All ducks float,
11 public void setQuackBehavior(QuackBehavior qb) { 26 even decoys!");
12 quackBehavior = qb; 27 }
13 } 28 }
14
15 abstract void display();

Note: code to interface, delegation, encapsulation, and ability to change behaviors dynamically

Object-Oriented Programming 27
Design Pattern by Example RubberDuck.java

MallardDuck.java RedHeadDuck.java
1 public class MallardDuck extends Duck { 1 public class RedHeadDuck extends Duck {
2 2
3 public MallardDuck() { 3 public RedHeadDuck() {
4 4
5 quackBehavior = new Quack(); 5 flyBehavior = new FlyWithWings();
6 flyBehavior = new FlyWithWings(); 6 quackBehavior = new Quack();
7 7
8 } 8 }
9 9
10 public void display() { 10 public void display() {
11 System.out.println("I'm a real 11 System.out.println("I'm a real
12 Mallard duck"); 12 Red Headed duck");
13 } 13 }
14 } 14 }

Object-Oriented Programming 28
Design Pattern by Example RubberDuck.java

RubberDuck.java DecoyDuck.java
1 public class RubberDuck extends Duck { 1 public class DecoyDuck extends Duck {
2 2 public DecoyDuck() {
3 public RubberDuck() { 3
4 flyBehavior = new FlyNoWay(); 4 setFlyBehavior(new FlyNoWay());
5 quackBehavior = new Squeak(); 5 setQuackBehavior(new MuteQuack());
6 } 6
7 7 }
8 public RubberDuck(FlyBehavior flyBehavior, 8
9 QuackBehavior quackBehavior) { 9 public void display() {
10 this.flyBehavior = flyBehavior; 10 System.out.println("I'm a duck Decoy");
11 this.quackBehavior = quackBehavior; 11 }
12 } 12 }
13
14 public void display() {
15 System.out.println("I'm a rubber duckie");
16 }
17 }

Object-Oriented Programming 29
Design Pattern by Example DuckSimulator.java (I)

DuckSimulator.java
1 import java.util.*;
2
3 public class DuckSimulator {
4 public static void main(String[] args) {
5 List<Duck> ducks = new LinkedList<>();
6
7 Duck myDuck = new RubberDuck();
8 Note: all variables are of type Duck, not the
9 ducks.add(new MallardDuck());
10 ducks.add(new DecoyDuck()); specific subtypes; “code to interface” in action
11 ducks.add(new RedheadDuck());
12 ducks.add(myDuck);
13
14 processDucks(ducks);
15
16 // Change my ducks' behavior dynamically to make a rubber
17 // duck that can fly rocket powered and speak
18 myDuck.setFlyBehavior(new FlyRocketPowered());
19 myDuck.setQuackBehavior(new Speak());
Note: here we see the power of delegation.
20 We can change behaviors at run-time
21 processDucks(ducks);
22 }

Object-Oriented Programming 30
Design Pattern by Example DuckSimulator.java (II)

FlyBehavior.java (continue)
1 public static void processDucks(List<Duck> ducks) {
2 for (Duck duck : ducks) {
3 System.out.println("--------------------");
4 System.out.println("Name: " + duck.getClass().getName());
5 duck.display();
6 duck.performQuack();
7 duck.performFly();
8 duck.swim();
9 }
10 Because of abstraction and
11 System.out.println("Done processing ducks\n"); polymorphism, processDucks()
12 } consists of nice, clean, robust,
13 }
and extensible code!

Object-Oriented Programming 31
Design Pattern by Example Not Completely Decoupled

▪ Is DuckSimulator completely decoupled from the Duck subclasses?


• All of its variables are of type Duck

▪ No!
• The subclasses are still coded into DuckSimulator
- Duck myDuck = new RubberDuck();

▪ This is a type of coupling…


• Fortunately, we can eliminate this type of coupling if needed, using a pattern called Factory.
- We’ll see Factory in action later

Object-Oriented Programming 32
Design Patterns Strategy Pattern

Strategy Pattern

Object-Oriented Programming 33
Strategy Pattern Meet the Strategy Design Pattern

▪ The solution that we applied to this design problem is known as the Strategy Design
Pattern

• It features the following design concepts/principles:


- Encapsulate what varies
- Code to an Interface
- Delegation
- Favor Delegation over Inheritance

• Definition: The Strategy pattern defines a family of algorithms, encapsulates each one, and
makes them interchangeable. Strategy lets the algorithm vary independently from clients that
use it

Object-Oriented Programming 34
Strategy Pattern Structure of Strategy

▪ Algorithm is pulled out of Host. Client only makes use of the public interface of
Algorithm and is not tied to concrete subclasses.
▪ Client can change its behavior by switching among the various concrete algorithms

Object-Oriented Programming 35
Strategy Pattern Review of Delegate

▪ Purpose of Delegate:
• Allow an object’s behavior to be customized without forcing a developer to create a subclass
that overrides default behavior

▪ Structure
• Host object; Delegate Interface; Delegate object; Client
• Client invokes method on Host; Host checks to see if Delegate handles this method; if so, it
routes the call to the Delegate; if not, it provides default behavior for the method

Object-Oriented Programming 36
Strategy Pattern Structure of Delegate

▪ Here, if Client invokes methodA() on Host, the Delegate’s customizeMethodA() will be


invoked at some point to help customize Host’s behavior for methodA();

Object-Oriented Programming 37
Design Patterns Adapter Pattern

Adapter Pattern

Object-Oriented Programming 38
Adapter Pattern Adapters in the Real World

▪ Our next pattern provides steps


for converting an incompatible
interface with an existing system
into a different interface that is
compatible
• Real world example: AC power
adapters
• Electronic products made for the
USA cannot be used directly with
outlets found in most other parts
of the world
- To use these products outside the
US, you need an AC power adapter

Object-Oriented Programming 39
Adapter Pattern Software Adapters (I)

▪ Pre-condition: You are maintaining an existing system that makes use of a third-party class
library from vendor A

▪ Stimulus: Vendor A goes belly up and corporate policy does not allow you to make use of
an unsupported class library

▪ Response: Vendor B provides a similar class library but its interface is completely different
from the interface provided by vendor A

▪ Assumptions: You don’t want to change your code, and you can’t change vendor B’s code

▪ Solution?: Write new code that adapts vendor B’s interface to the interface expected by
your original code

Object-Oriented Programming 40
Adapter Pattern Software Adapters (II)

Object-Oriented Programming 41
Adapter Pattern Software Adapters (III)

…plug it in

Benefit: Existing system and new vendor library do not change — new code is isolated
within the adapter

Object-Oriented Programming 42
Adapter Pattern Example: A Turkey Amongst Ducks! (I)

▪ If it walks like a duck and quacks like a duck, then it must be a duck!

Or…

▪ It might be a turkey wrapped with a duck adapter!

Object-Oriented Programming 43
Adapter Pattern Example: A Turkey Amongst Ducks! (II)

▪ A slightly different duck model


Duck.java
1 public interface Duck {
2 public void quack();
3 public void fly();
4 }

MallarDuck.java
1 public class MallardDuck implements Duck {
2 public void quack() {
3 System.out.println("Quack");
4 }
5
6 public void fly() {
7 System.out.println("I'm flying");
8 }
9 }

Object-Oriented Programming 44
Adapter Pattern Example: A Turkey Amongst Ducks! (III)

▪ An interloper wants to invade the simulator


Turkey.java
1 public interface Turkey {
2 public void gobble();
3 public void fly();
4 }

WildTurkey.java
1 public class WildTurkey implements Turkey {
2 public void gobble() {
3 System.out.println("Gobble Gobble"); But the duck simulator
4 }
5
doesn’t know how to handle
6 public void fly() { turkeys, only ducks!
7 System.out.println("I'm flying a short distance");
8 }
9 }

Object-Oriented Programming 45
Adapter Pattern Example: A Turkey Amongst Ducks! (IV)

▪ Solution: Write an adapter that makes a turkey look like a duck


TurkeyAdapter.java 1. Adapter implements target
1 public class TurkeyAdapter implements Duck { interface (Duck)
2 private Turkey turkey;
3
4 public TurkeyAdapter(Turkey turkey) { 2. Adaptee (turkey) is passed via
5 this.turkey = turkey; constructor and stored internally
6 }
7
8 public void quack() { 3. Calls by client code are delegated
9 turkey.gobble(); to the appropriate methods in the
10 } adaptee
11
12 public void fly() {
13 for (int i = 0; i < 5; i++) { 4. Adapter is full-fledged class, could
14 turkey.fly(); contains additional vars and
15 }
16 } methods to get its job done; can be
17 } used polymorphically as a Duck

Object-Oriented Programming 46
Adapter Pattern DuckSimulator.java

DuckSimulator.java
1 import java.util.LinkedList;
2 import java.util.List;
3
4 public class DuckSimulator {
5 public static void main(String[] args) {
6 MallardDuck mallardDuck = new MallardDuck();
7
8 WildTurkey wildTurkey = new WildTurkey();
9 Duck turkeyAdapter = new TurkeyAdapter(wildTurkey);
10
11 List<Duck> ducks = new LinkedList<Duck>();
12 ducks.add(mallardDuck);
13 ducks.add(turkeyAdapter);
14
15 for (Duck duck : ducks) {
16 duck.quack();
17 duck.fly();
18 }
19 }
20 }

Object-Oriented Programming 47
Adapter Pattern The Adapter Pattern explained

Here’s how the Client uses the Adapter

1. The client makes a request to the


adapter by calling a method on it using
the target interface.

2. The adapter translates the request


into one or more calls on the adaptee
using the adaptee interface.

3. The client receives the results of the


call and never knows there is an
adapter doing the translation.

Note that the Client and Adaptee are


decoupled – neither knows about the
other.

Object-Oriented Programming 48
Adapter Pattern Definition (I)

▪ The Adapter pattern converts the interface of a class into another interface that clients
expect. Adapter lets classes work together that couldn’t otherwise because of
incompatible interfaces.

• The client makes a request on the adapter by invoking a method from the target interface
on it
• The adapter translates that request into one or more calls on the adaptee using the adaptee
interface
• The client receives the results of the call and never knows there is an adapter doing the
translation

Object-Oriented Programming 49
Adapter Pattern Definition (II)

Object-Oriented Programming 50
Adapter Pattern Structure (I)

Client codes to an interface,


not an implementation.
Allows creation of multiple
adapter classes, if needed.

Adapter makes use of


delegation to access the
behavior of Adaptee. We can
pass any subclass of Adaptee
to the Adapter, if needed.

Object-Oriented Programming 51
Adapter Pattern Structure (II)

Requires use of multiple inheritance,


but now adapter does not need to
re-implement target and/or adaptee
behavior.

It simply overrides or inherits that


behavior instead.

Object-Oriented Programming 52
Adapter Pattern Real World Adapters

▪ Before Java’s new collection classes, iteration over a collection occurred via
java.util.Enumeration
• hasMoreElements() : boolean
• nextElement() : Object

▪ With the collection classes, iteration was moved to a new interface: java.util.Iterator
• hasNext(): boolean
• next(): Object
• remove(): void

▪ There’s a lot of code out there that makes use of the Enumeration interface
• New code can still make use of that code by creating an adapter that converts from the Enumeration
interface to the Iteration interface

Object-Oriented Programming 53
Design Patterns Facade Pattern

Facade Pattern

Object-Oriented Programming 54
Façade Pattern Façade (I)

▪ “Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-


level interface that makes the subsystem easier to use.”
• Design Patterns, Gang of Four, 1995

▪ There can be significant benefit in wrapping a complex subsystem with a simplified


interface
• If you don’t need the advanced functionality or fine-grained control of the former, the latter
makes life easy

Object-Oriented Programming 55
Façade Pattern Structure

Object-Oriented Programming 56
Façade Pattern Façade (II)

▪ Façade works best when you are accessing a subset of the system’s functionality
• You can add new features by adding them to the Façade (not the subsystem); you still get a
simpler interface

▪ Façade not only reduces the number of methods you are dealing with but also the
number of classes
• Imagine having to pull Employees out of Divisions that come from Companies that you pull from
a Database
- A Façade in this situation can fetch Employees directly

Object-Oriented Programming 57
Façade Pattern Example (Without a Façade)

▪ Without a Façade, Client contacts


the Database to retrieve Company
objects. It then retrieves Division
objects from them and finally
gains access to Employee objects.

▪ It uses four classes.

Object-Oriented Programming 58
Façade Pattern Example (With a Façade)

▪ With a Façade, the Client is shielded from most of the classes. It uses the Database Façade
to retrieve Employee objects directly.

Object-Oriented Programming 59
Façade Pattern Façade Example (I)

▪ Imagine a library of classes with a


complex interface and/or complex
interrelationships
• Home Theater System
- Amplifier, DvdPlayer, Projector,
CdPlayer, Tuner, Screen,
PopcornPopper, and TheaterLights
- each with its own interface and
interclass dependencies

That’s a lot of classes, a lot of interactions,


and a big set of interfaces to learn and use

Object-Oriented Programming 60
Façade Pattern Façade Example (II)

Watching a movie (the hard way)


There’s just one thing – to watch the movie, you need to perform a few tasks:

1. Turn on the popcorn popper 8. Turn the sound amplifier on


2. Start the popper popping 9. Set the amplifier to DVD input
3. Dim the lights 10. Set the amplifier to surround sound
4. Put the screen down 11. Set the amplifier volume to medium (5)
5. Turn the projector on 12. Turn the DVD Player on
6. Set the projector input to DVD 13. Start the DVD Player playing
7. Put the projector on wide-screen mode

Object-Oriented Programming 61
Façade Pattern Façade Example (III)

Let’s check out those same tasks in terms of the classes and the method calls needed to
perform them:

Object-Oriented Programming 62
Façade Pattern Façade Example (IV)

Object-Oriented Programming 63
Façade Pattern Façade Example (V)

Object-Oriented Programming 64
Façade Pattern Façade Example (VI)

▪ For this example, we can place high level methods…


• like “watch movie”, “reset system”, “play cd”

… in a façade object and encode all of the steps for each high level service in the façade;

▪ Client code is simplified and dependencies are reduced


• A façade not only simplifies an interface, it decouples a client from a subsystem of
components

▪ Indeed, Façade lets us encapsulate subsystems, hiding them from the rest of the system

Object-Oriented Programming 65
Façade Pattern Façade vs. Adapter Comparison (I)

▪ To many people, two patterns Adapter and Façade appear to be similar


• They both act as wrappers of a pre-existing class
• They both take an interface that we don’t want and convert it to an interface that we can use

▪ With Façade, the intent is to simplify the existing interface

▪ With Adapter, we have a target interface that we are converting to


• In addition, we often want the adapter to plug into an existing framework and behave
polymorphically

Object-Oriented Programming 66
Façade Pattern Façade vs. Adapter Comparison (II)

▪ Superficial difference
• Façade hides many classes
• Adapter hides only one

▪ But
• a Façade can simplify a single, very complex object
• an Adapter can wrap multiple objects at once in order to access all the functionality it needs

▪ The key is simplify (façade) vs. convert (adapter)

Object-Oriented Programming 67
Façade Pattern Demonstration: Home Theater

PopcornPopper.java Screen.java
1 public class PopcornPopper { 1 public class Screen {
2 String description; 2 String description;
3
4 3
public PopcornPopper(String description) {
5 this.description = description; 4 public Screen(String description) {
6 } 5 this.description = description;
7 6 }
8 public void on() { 7
9 System.out.println(description + " on"); 8 public void up() {
10 }
11 9 System.out.println(description + " going up");
12 public void off() { 10 }
13 System.out.println(description + " off"); 11
14 } 12 public void down() {
15 13 System.out.println(description + " going down");
16 public void pop() { 14 }
17 System.out.println(description + " popping popcorn!");
18 15
}
19 16 public String toString() {
20 public String toString() { 17 return description;
21 return description; 18 }
22 } 19 }
23 }

Object-Oriented Programming 68
Façade Pattern Demonstration: Home Theater

Projector.java TheaterLights.java
1 public class Projector { 1 public class TheaterLights {
2 String description; 2 String description;
3 DvdPlayer dvdPlayer;
4 3
5 public Projector(String description, DvdPlayer dvdPlayer) { 4 public TheaterLights(String description) {
6 this.description = description; 5 this.description = description;
7 this.dvdPlayer = dvdPlayer; 6 }
8 } 7
9
10 8 public void on() {
public void on() {
11 System.out.println(description + " on"); 9 System.out.println(description + " on");
12 } 10 }
13 11
14 public void off() { 12 public void off() {
15 System.out.println(description + " off");
16 13 System.out.println(description + " off");
}
17 14 }
18 public void wideScreenMode() { 15
19 System.out.println(description + " in widescreen mode (16x9 aspect ratio)"); 16 public void dim(int level) {
20 } 17 System.out.println(description + " dimming to "
21
22 18 + level + "%");
public void tvMode() {
23 System.out.println(description + " in tv mode (4x3 aspect ratio)"); 19 }
24 } 20
25 21 public String toString() {
26 public String toString() { 22 return description;
27 return description;
28 23 }
}
29 } 24 }

Object-Oriented Programming 69
Façade Pattern Demonstration: Home Theater

HomeTheaterFacade.java HomeTheaterFacade.java (continue)


1 public class HomeTheaterFacade { 29 public void watchMovie(String movie) {
2 Amplifier amp; 30 System.out.println("Get ready to watch a movie...");
3 Tuner tuner; 31 popper.on();
4 DvdPlayer dvd; 32 popper.pop();
5 CdPlayer cd; 33 lights.dim(10);
6 Projector projector; 34 screen.down();
7 TheaterLights lights; 35 projector.on();
8 Screen screen; 36 projector.wideScreenMode();
9 PopcornPopper popper; 37 amp.on();
10
38 amp.setDvd(dvd);
11 public HomeTheaterFacade(Amplifier amp,
12 39 amp.setSurroundSound();
Tuner tuner,
13 40 amp.setVolume(5);
DvdPlayer dvd,
14 41 dvd.on();
CdPlayer cd,
15 Projector projector, 42 dvd.play(movie);
16 Screen screen, 43 }
17 TheaterLights lights, 44
18 PopcornPopper popper) { 45 public void endMovie() {
19 46 System.out.println("Shutting movie theater down...");
20 this.amp = amp; 47 popper.off();
21 this.tuner = tuner; 48 lights.on();
22 this.dvd = dvd; 49 screen.up();
23 this.cd = cd; 50 projector.off();
24 this.projector = projector; 51 amp.off();
25 this.screen = screen; 52 dvd.stop();
26 this.lights = lights; 53 dvd.eject();
27 this.popper = popper; 54 dvd.off();
28 } 55 }

Object-Oriented Programming 70
Façade Pattern Demonstration: Home Theater

WeatherStation.java
1 public class HomeTheaterTestDrive {
2
3 public static void main(String[] args) {
4 Amplifier amp = new Amplifier("Top-O-Line Amplifier");
5 Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp);
6 DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp);
7 CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp);
8 Projector projector = new Projector("Top-O-Line Projector", dvd);
9 TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
10 Screen screen = new Screen("Theater Screen");
11 PopcornPopper popper = new PopcornPopper("Popcorn Popper");
12
13 HomeTheaterFacade homeTheater = new HomeTheaterFacade(
14 amp, tuner, dvd, cd, projector, screen, lights, popper);
15
16 homeTheater.watchMovie("Raiders of the Lost Ark");
17 homeTheater.endMovie();
18 }
19 }

Object-Oriented Programming 71
Design Patterns Observer Pattern

Observer Pattern

Object-Oriented Programming 72
Observer Pattern

▪ Don’t miss out when something interesting (in your system) happens!
• The observer pattern allows objects to keep other objects informed about events
occurring within a software system (or across multiple systems)

• It’s dynamic in that an object can choose to receive or not receive notifications at run-
time

• Observer happens to be one of the most heavily used patterns in the Java Development
Kit
- And indeed is present in many frameworks

Object-Oriented Programming 73
Observer Pattern Weather Monitoring Example

▪ We need to pull information from the station and then generate “current conditions,
weather stats, and a weather forecast”.

Object-Oriented Programming 74
Observer Pattern WeatherData Skeleton

▪ We receive a partial implementation of the WeatherData class from our client.

▪ They provide three getter methods for the sensor values and an empty
measurementsChanged() method that is guaranteed to be called whenever a sensor
provides a new value

▪ We need to pass these values to our three displays… so that’s simple!

Object-Oriented Programming 75
Observer Pattern First pass at measurementsChanged

WeatherData.java Problems?
...
public void measurementsChanged() {
float temp = getTemperature(); 1. The number and type of displays
float humidity = getHumidity(); may vary.
float pressure = getPressure();
These three displays are hard coded
currentConditionsDisplay.update(temp, humidity, pressure);
statisticsDisplay.update(temp, humidity, pressure); with no easy way to update them.
forecastDisplay.update(temp, humidity, pressure);
}
...
2. Coding to implementations, not
an interface!
Each implementation has adopted
the same interface, so this will make
translation easy!

Object-Oriented Programming 76
Observer Pattern Observer Pattern example

▪ This situation can benefit from use of the observer pattern

• This pattern is similar to subscribing to a hard copy newspaper


- A newspaper comes into existence and starts publishing editions
- You become interested in the newspaper and subscribe to it
- Any time an edition becomes available, you are notified (by the fact that it is delivered to you)
- When you don’t want the paper anymore, you unsubscribe
- The newspaper’s current set of subscribers can change at any time

• Observer is just like this but we call the publisher the “subject” and we refer to subscribers as
“observers”

Object-Oriented Programming 77
Observer Pattern Observer in Action (I)

Object-Oriented Programming 78
Observer Pattern Observer in Action (II)

Object-Oriented Programming 79
Observer Pattern Observer in Action (III)

Object-Oriented Programming 80
Observer Pattern Observer in Action (IV)

Object-Oriented Programming 81
Observer Pattern Definition and Structure

▪ The Observer Pattern defines a one-to-many dependency between a set of objects, such
that when one object (the subject) changes all of its dependents (observers) are notified
and updated automatically

Object-Oriented Programming 82
Observer Pattern Observer Benefits

▪ Observer affords a loosely coupled interaction between subject and observer


• This means they can interact with very little knowledge about each other
▪ Consider
• The subject only knows that observers implement the Observer interface
- We can add/remove observers of any type at any time
- We never have to modify subject to add a new type of observer
• We can reuse subjects and observers in other contexts
- The interfaces plug-and-play anywhere observer is used
• Observers may have to know about the ConcreteSubject class if it provides many different state-
related methods
- Otherwise, data can be passed to observers via the update() method

Object-Oriented Programming 83
Observer Pattern Demonstration: Weather Monitoring

Subject.java
1 public interface Subject {
2 public void registerObserver(Observer o);
3 public void removeObserver(Observer o);
4 public void notifyObservers();
5 }

Observer.java
1 public interface Observer {
2 public void update(float temp, float humidity, float pressure);
3 }

DisplayElement.java
1 public interface DisplayElement {
2 public void display();
3 }

Object-Oriented Programming 84
Observer Pattern Demonstration: Weather Monitoring

WeatherData.java WeatherData.java (continue)


1 public class WeatherData implements Subject { 27 public void measurementsChanged() {
2 private ArrayList<Observer> observers; 28 notifyObservers();
3 private float temperature; 29 }
4 private float humidity; 30
5 private float pressure; 31 public void setMeasurements(float temperature,
6 32 float humidity,
7 public WeatherData() { 33 float pressure) {
8 observers = new ArrayList<Observer>(); 34 this.temperature = temperature;
9 } 35 this.humidity = humidity;
10 36 this.pressure = pressure;
11 public void registerObserver(Observer o) { 37 measurementsChanged();
12 observers.add(o); 38 }
13 } 39
14 40 // other WeatherData methods here
15 public void removeObserver(Observer o) { 41 public float getTemperature() {
16 int i = observers.indexOf(o); 42 return temperature;
17 if (i >= 0) { 43 }
18 observers.remove(i); 44
19 } 45 public float getHumidity() {
20 } 46 return humidity;
21 47 }
22 public void notifyObservers() { 48
23 for (Observer o: observers) { 49 public float getPressure() {
24 o.update(temperature, humidity, pressure); 50 return pressure;
25 } 51 }
26 } 52 }

Object-Oriented Programming 85
Observer Pattern Demonstration: Weather Monitoring

ForecastDisplay.java StatisticsDisplay.java
1 import java.util.*; 1 public class StatisticsDisplay implements Observer, DisplayElement {
2 2 private float maxTemp = 0.0f;
3 public class ForecastDisplay implements Observer, DisplayElement { 3 private float minTemp = 200;
4 private float currentPressure = 29.92f; 4 private float tempSum= 0.0f;
5 private float lastPressure; 5 private int numReadings;
6 private WeatherData weatherData; 6 private WeatherData weatherData;
7 7
8 public ForecastDisplay(WeatherData weatherData) { 8 public StatisticsDisplay(WeatherData weatherData) {
9 this.weatherData = weatherData; 9 this.weatherData = weatherData;
10 weatherData.registerObserver(this); 10 weatherData.registerObserver(this);
11 } 11 }
12 12
13 public void update(float temp, float humidity, float pressure) { 13 public void update(float temp, float humidity, float pressure) {
14 lastPressure = currentPressure; 14 tempSum += temp;
15 currentPressure = pressure; 15 numReadings++;
16 16
17 display(); 17 if (temp > maxTemp) {
18 } 18 maxTemp = temp;
19 19 }
20 public void display() { 20 if (temp < minTemp) {
21 System.out.print("Forecast: "); 21 minTemp = temp;
22 if (currentPressure > lastPressure) { 22 }
23 System.out.println("Improving weather on the way!"); 23 display();
24 } else if (currentPressure == lastPressure) { 24 }
25 System.out.println("More of the same"); 25
26 } else if (currentPressure < lastPressure) { 26 public void display() {
27 System.out.println("Watch out for cooler, rainy weather"); 27 System.out.println("Avg/Max/Min temperature = "
28 } 28 + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
29 } 29 }
30 } 30 }

Object-Oriented Programming 86
Observer Pattern Demonstration: Weather Monitoring

WeatherStation.java
1 import java.util.*;
2
3 public class WeatherStation {
4
5 public static void main(String[] args) {
6 WeatherData weatherData = new WeatherData();
7
8 CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
9 StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
10 ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
11
12 System.out.println("----------------------------------------");
13 weatherData.setMeasurements(80, 65, 30.4f);
14 System.out.println("----------------------------------------");
15 weatherData.setMeasurements(82, 70, 29.2f);
16 System.out.println("----------------------------------------");
17 weatherData.setMeasurements(78, 90, 29.2f);
18 System.out.println("----------------------------------------");
19 }
20 }

Object-Oriented Programming 87
Design Patterns

Factory Pattern

Object-Oriented Programming 88
Factory Pattern Factory Patterns: The Problem with “new”

▪ Each time we invoke the “new” command to create a new object, we violate the “code to
an Interface” design principle
▪ Example
Duck duck = new DecoyDuck();
▪ Even though our variable uses an “interface”, this code depends on “DecoyDuck”
▪ In addition, if you have code that instantiates a particular subtype based on the current
state of the program, then the code depends on each concrete class

Obvious problems:
if (hunting) {
▪ needs to be recompiled each time a dependent changes;
return new DecoyDuck()
▪ add new classes -> change this code
} else {
▪ remove existing classes -> change this code
return new RubberDuck()
} This means that this code violates the open-closed principle
and the “encapsulate what varies” design principle

Object-Oriented Programming 89
Factory Pattern PizzaStore Example

▪ We have a pizza store program that PizzaStore.java


wants to separate the process of
1 public class PizzaStore {
creating a pizza from the process of 2
preparing/ordering a pizza 3 Pizza orderPizza(String type) { Creation
4 Pizza pizza;
5 if (type.equals("cheese")) {
▪ Initial code: mixes the two processes 6 pizza = new CheesePizza();
7 } else if (type.equals("greek")) {
8 pizza = new GreekPizza();
9 } else if (type.equals("pepperoni")) {
10 pizza = new PepperoniPizza();
11 }
12 pizza.prepare();
13 pizza.bake(); This code is NOT closed for
Excellent example of 14 pizza.cut(); modification. If the Pizza
“coding to an interface” 15 pizza.box(); Store changes its pizza
Preparation
16 return pizza; offerings, we have to open
17 } this code and modify it.
18 }

Object-Oriented Programming 90
Factory Pattern Encapsulate Creation Code

PizzaStore.java ▪ A simple way to encapsulate this code is to


1 public class PizzaStore {
put it in a separate class
2 • That new class depends on the concrete
3 private SimplePizzaFactory factory;
4
classes, but those dependencies no longer
5 public PizzaStore(SimplePizzaFactory factory) { impact the preparation code
6 this.factory = factory;
7 } SimplePizzaFactory.java
8
9 public Pizza orderPizza(String type) { 1 public class SimplePizzaFactory {
10 2
11 Pizza pizza = factory.createPizza(type); 3 public Pizza createPizza(String type) {
12 pizza.prepare(); 4 if (type.equals("cheese")) {
13 pizza.bake(); 5 return new CheesePizza();
14 pizza.cut(); 6 } else if (type.equals("greek")) {
15 pizza.box(); 7 return new GreekPizza();
16 8 } else if (type.equals("pepperoni")) {
17 return pizza; 9 return new PepperoniPizza();
18 } 10 }
19 } 11 }
12 }

Object-Oriented Programming 91
Factory Pattern Factory

▪ The new object is called a Factory. SimplePizzaFactory.java


1 public class SimplePizzaFactory {
2
▪ Factories handle the details of object creation. 3 public Pizza createPizza(String type) {
Once we have a SimplePizzaFactory, our 4 if (type.equals("cheese")) {
5 return new CheesePizza();
orderPizza() method becomes a client of that 6 } else if (type.equals("greek")) {
object. Anytime it needs a pizza, it asks the pizza 7 return new GreekPizza();
factory to make one. 8 } else if (type.equals("pepperoni")) {
9 return new PepperoniPizza();
10 }
11 }
▪ Now the orderPizza() method just cares that it 12 }
gets a pizza that implements the Pizza interface
Here’s our new class, the
so that it can call prepare(), bake(), cut(), and
SimplePizzaFactory. It has one
box().
job in life: creating pizzas for its
clients.

Object-Oriented Programming 92
Factory Pattern Demonstration

Pizza.java Pizza.java (continue)


1 import java.util.ArrayList; 21 public void cut() {
2 import java.util.List; 22 System.out.println("Cutting " + name);
3 23 }
4 public abstract class Pizza { 24
5 25 public void box() {
String name;
6 26 System.out.println("Boxing " + name);
String dough;
27 }
7 String sauce; 28
8 List<String> toppings = new ArrayList<>(); 29 public String toString() {
9 30 // code to display pizza name and ingredients
10 public String getName() { 31 StringBuffer display = new StringBuffer();
11 return name; 32 display.append("---- " + name + " ----\n");
12 } 33 display.append(dough + "\n");
13 34 display.append(sauce + "\n");
14 public void prepare() { 35 for (int i = 0; i < toppings.size(); i++) {
15 System.out.println("Preparing " + name); 36 display.append((String) toppings.get(i) + "\n");
16 } 37 }
17 38
18 public void bake() { 39 return display.toString();
19 40 }
System.out.println("Baking " + name);
20 41 }
}

Object-Oriented Programming 93
Factory Pattern Demonstration

PizzaTestDrive.java
1 public class PizzaTestDrive {
2
3 public static void main(String[] args) {
4 System.out.println("");
5 SimplePizzaFactory factory = new SimplePizzaFactory();
6 PizzaStore store = new PizzaStore(factory);
7
8 Pizza pizza = store.orderPizza("cheese");
9 System.out.println("We ordered a " + pizza.getName() + "\n");
10
11 pizza = store.orderPizza("veggie");
12 System.out.println("We ordered a " + pizza.getName() + "\n");
13 }
14 }

Object-Oriented Programming 94
Factory Pattern Class Diagram of New Solution

While this is nice, it is not as flexible as it can be: to increase flexibility we need to look at two
design patterns: Factory Method and Abstract Factory

Object-Oriented Programming 95
Factory Method Pattern Factory Method

▪ To demonstrate the Factory Method pattern, One franchise wants a factory that
the pizza store example evolves makes NY-style pizzas: thin crust, tasty
sauce, and just a little cheese.
• to include the notion of different
franchises
• that exist in different parts of the country
(California, New York, Chicago)

▪ Each franchise needs its own factory to


match the proclivities of the locals
• However, we want to retain the
preparation process that has made
PizzaStore such a great success Another franchise wants a factory
that makes Chicago-style pizzas;
their customers like pizzas with thick
crust, rich sauce, and tons of cheese.

Object-Oriented Programming 96
Factory Method Pattern Factory Method

▪ The Factory Method design pattern allows you to do this by


• placing abstract “code to an interface” code in a superclass
• placing object creation code in a subclass

▪ What we’re going to do is put the createPizza() method back into PizzaStore, but this time
as an abstract method
• PizzaStore becomes an abstract class with an abstract createPizza() method
• We then create subclasses that override createPizza() for each region

Object-Oriented Programming 97
Factory Method Pattern New PizzaStore Class

PizzaStore.java Factory Method


1 public abstract class PizzaStore {
2 This class is a (very simple) OO framework. The
3 abstract Pizza createPizza(String item); framework provides one service: “order pizza.”
4
5 public Pizza orderPizza(String type) {
6 The framework invokes the createPizza factory
Pizza pizza = createPizza(type);
7 System.out.println("--- Making a " method to create a pizza that it can then
8 + pizza.getName() + " ---"); prepare using a well-defined, consistent
9 process.
10 pizza.prepare();
11 pizza.bake(); A “client” of the framework will subclass this
12 pizza.cut();
13 pizza.box();
class and provide an implementation of the
14 createPizza method.
15 return pizza;
16 } Any dependencies on concrete “product”
17 } classes are encapsulated in the subclass.

Object-Oriented Programming 98
Factory Method Pattern New York Pizza Store

NYPizzaStore.java ▪ Nice and simple. If you want a NY-


1 public class NYPizzaStore extends PizzaStore { style pizza, you create an instance
2 of this class and call orderPizza()
3 Pizza createPizza(String item) {
4 if (item.equals("cheese")) { passing in the type. The subclass
5 return new NYStyleCheesePizza(); makes sure that the pizza is
6 } else if (item.equals("veggie")) {
7 return new NYStyleVeggiePizza();
created using the correct style.
8 } else if (item.equals("clam")) {
9 return new NYStyleClamPizza();
10 } else if (item.equals("pepperoni")) {
11 return new NYStylePepperoniPizza();
12 } else {
13 return null;
14 }
15 }
16 }

Object-Oriented Programming 99
Factory Method Pattern Chicago Pizza Store

ChicagoPizzaStore.java ▪ If you need a different style,


1 public class ChicagoPizzaStore extends PizzaStore { create a new subclass.
2
3 Pizza createPizza(String item) {
4 if (item.equals("cheese")) {
5 return new ChicagoStyleCheesePizza();
6 } else if (item.equals("veggie")) {
7 return new ChicagoStyleVeggiePizza();
8 } else if (item.equals("clam")) {
9 return new ChicagoStyleClamPizza();
10 } else if (item.equals("pepperoni")) {
11 return new ChicagoStylePepperoniPizza();
12 } else {
13 return null;
14 }
15 }
16 }

Object-Oriented Programming 100


Factory Method Pattern A couple of the concrete product classes

NYStylePepperoniPizza.java ChicagoStylePepperoniPizza.java
1 public class NYStylePepperoniPizza extends Pizza { 1 public class ChicagoStylePepperoniPizza extends Pizza {
2 2
3 public NYStylePepperoniPizza() { 3 public ChicagoStylePepperoniPizza() {
4 name = "NY Style Pepperoni Pizza"; 4 name = "Chicago Style Pepperoni Pizza";
5 dough = "Thin Crust Dough"; 5 dough = "Extra Thick Crust Dough";
6 sauce = "Marinara Sauce"; 6 sauce = "Plum Tomato Sauce";
7 7
8 toppings.add("Grated Reggiano Cheese"); 8 toppings.add("Shredded Mozzarella Cheese");
9 toppings.add("Sliced Pepperoni"); 9 toppings.add("Black Olives");
10 toppings.add("Garlic"); 10 toppings.add("Spinach");
11 toppings.add("Onion"); 11 toppings.add("Eggplant");
12 toppings.add("Mushrooms"); 12 toppings.add("Sliced Pepperoni");
13 toppings.add("Red Pepper"); 13 }
14 } 14
15 15 void cut() {
16 void cut() { 16 System.out.println("Cutting the pizza
17 System.out.println("Cutting the pizza 17 into square slices");
18 into 8 slices"); 18 }
19 } 19 }
20 }

Object-Oriented Programming 101


Factory Method Pattern Definition and Structure

The Factory Method design pattern defines an interface for creating an object, but lets subclasses
decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.

Factory Method leads to the creation of parallel class hierarchies; ConcreateCreators produce
instances of ConcreteProducts that are operated on by Creators via the Product interface

Object-Oriented Programming 102


Factory Method Pattern Dependency Inversion Principle (I)

▪ Factory Method is one way of following the dependency inversion principle


• “Depend upon abstractions. Do not depend upon concrete classes.”

▪ Normally “high-level” classes depend on “low-level” classes;


• Instead, they BOTH should depend on an abstract interface

Object-Oriented Programming 103


Factory Method Pattern Dependency Inversion Principle: Pictorially

Here we have a client class in an “upper”


level of our design depending on a
concrete class that is “lower” in the design

Object-Oriented Programming 104


Factory Method Pattern Dependency Inversion Principle: Pictorially

Instead, create an interface that lives in the


upper level that hides the concrete classes
in the lower level - “code to an interface”

Object-Oriented Programming 105


Factory Method Pattern Dependency Inversion Principle (II)

▪ Factory Method is one way of following the dependency inversion principle


• “Depend upon abstractions. Do not depend upon concrete classes.”

▪ Normally “high-level” classes depend on “low-level” classes;


• Instead, they BOTH should depend on an abstract interface

▪ DependentPizzaStore depends on eight concrete Pizza subclasses


• PizzaStore, however, depends on the Pizza interface
- as do the Pizza subclasses

▪ In this design, PizzaStore (the high-level class) no longer depends on the Pizza subclasses
(the low level classes); they both depend on the abstraction “Pizza”.

Object-Oriented Programming 106


Factory Method Pattern Dependency Inversion Principle: How To?

▪ To achieve the dependency inversion principle in your own designs, follow these
GUIDELINES
• No variable should hold a reference to a concrete class
• No class should derive from a concrete class
• No method should override an implemented method of its base classes

▪ These are “guidelines” because if you were to blindly follow these instructions, you would
never produce a system that could be compiled or executed
• Instead use them as instructions to help optimize your design

▪ And remember, not only should low-level classes depend on abstractions, but high-level
classes should to… this is the very embodiment of “code to an interface”

Object-Oriented Programming 107


Factory Method Pattern Demonstration

▪ Lets look at some code

• The FactoryMethod directory of this lecture’s example source code contains an implementation
of the pizza store using the factory method design pattern
- It even includes a file called “DependentPizzaStore.java” that shows how the code would be
implemented without using this pattern

• DependentPizzaStore is dependent on 8 different concrete classes and 1 abstract interface


(Pizza)

• PizzaStore is dependent on just the Pizza abstract interface (nice!)


- Each of its subclasses is only dependent on 4 concrete classes
- furthermore, they shield the superclass from these dependencies

Object-Oriented Programming 108


Factory Method Pattern Moving On

▪ The factory method approach to the pizza store is a big success, allowing our company to
create multiple franchises across the country quickly and easily

• But (bad news): we have learned that some of the franchises


- while following our procedures (the abstract code in PizzaStore forces them to)
- are skimping on ingredients in order to lower costs and increase margins

• Our company’s success has always been dependent on the use of fresh, quality ingredients
- So, something must be done!

Object-Oriented Programming 109


Abstract Factory Pattern Abstract Factory to the Rescue!

▪ We will alter our design such that a factory is used to supply the ingredients that are
needed during the pizza creation process

• Since different regions use different types of ingredients, we’ll create region-specific subclasses
of the ingredient factory to ensure that the right ingredients are used

• But, even with region-specific requirements, since we are supplying the factories, we’ll make
sure that ingredients that meet our quality standards are used by all franchises
- They’ll have to come up with some other way to lower costs.

Object-Oriented Programming 110


Abstract Factory Pattern First, we Need a Factory Interface

PizzaIngredientFactory.java

1 public interface PizzaIngredientFactory {


2
3 public Dough createDough();
4
5 public Sauce createSauce();
6
Note the introduction of
7 public Cheese createCheese(); more abstract classes:
8 Dough, Sauce, Cheese, etc.
9 public Veggie[] createVeggies();
10
11 public Pepperoni createPepperoni();
12
13 public Clams createClams();
14 }

Object-Oriented Programming 111


Abstract Factory Pattern Second, we Implement a Region-Specific Factory

ChicagoPizzaIngredientFactory.java ▪ This factory ensures that quality


1 public class ChicagoPizzaIngredientFactory ingredients are used during the
2 implements PizzaIngredientFactory {
3 public Dough createDough() { pizza creation process…
4 return new ThickCrustDough();
5 }
6
7 public Sauce createSauce() {
▪ … while also taking into account
8 return new PlumTomatoSauce(); the tastes of people in Chicago
9 }
10
11
12
public Cheese createCheese() {
return new MozzarellaCheese();
▪ But how (or where) is this factory
13 } used?
14
15 public Veggies[] createVeggies() {
16 Veggies veggies[] = {new BlackOlives(),
17 new Spinach(),
18 new Eggplant()};
19 return veggies;
20 }
21 ...
22 }

Object-Oriented Programming 112


Abstract Factory Pattern Within Pizza Subclasses… (I)

Pizza.java
1 public abstract class Pizza {
2 String name;
3
4 Dough dough;
5 Sauce sauce;
6 Veggies veggies[]; First, alter the Pizza abstract base class to
7 Cheese cheese; make the prepare method abstract…
8 Pepperoni pepperoni;
9 Clams clam;
10
11 abstract void prepare();
12
13 void bake() {
14 System.out.println("Bake for 25 minutes at 350");
15 }
16
17 void cut() {
18 System.out.println("Cutting the pizza into diagonal slices");
19 }

Object-Oriented Programming 113


Abstract Factory Pattern Within Pizza Subclasses… (II)

CheesePizza.java
1 public class CheesePizza extends Pizza {
2 PizzaIngredientFactory ingredientFactory;
3
4 public CheesePizza(PizzaIngredientFactory ingredientFactory) {
5 this.ingredientFactory = ingredientFactory;
6 }
7
8 void prepare() {
9 System.out.println("Preparing " + name);
10 dough = ingredientFactory.createDough(); Then, update pizza subclasses to make
11 sauce = ingredientFactory.createSauce(); use of the factory!
12 cheese = ingredientFactory.createCheese();
13 } Note: we no longer need subclasses like
14 } NYCheesePizza and ChicagoCheesePizza
because the ingredient factory now
handles regional differences

Object-Oriented Programming 114


Abstract Factory Pattern One Last Step…

ChicagoPizzaStore.java
1 public class ChicagoPizzaStore extends PizzaStore {
2
3 protected Pizza createPizza(String item) {
4 Pizza pizza = null;
5 PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();
6
7 if (item.equals("cheese")) {
8 pizza = new CheesePizza(ingredientFactory);
9 pizza.setName("Chicago Style Cheese Pizza");
10 } else if (item.equals("veggie")) {
11 pizza = new VeggiePizza(ingredientFactory);
12 pizza.setName("Chicago Style Veggie Pizza");
13 } We need to update our PizzaStore
14 . . . subclasses to create the appropriate
15 } ingredient factory and pass it to each
16
17 return pizza; Pizza subclass within the createPizza
18 } method
19 }

Object-Oriented Programming 115


Abstract Factory Pattern Summary: What did we just do?

▪ We created an ingredient factory interface to allow for the creation of a family of


ingredients for a particular pizza

▪ This abstract factory gives us an interface for creating a family of products (e.g., NY pizzas,
Chicago pizzas)
• The factory interface decouples the client code from the actual factory implementations that
produce context-specific sets of products

▪ Our client code (PizzaStore) can then pick the factory appropriate to its region, plug it in,
and get the correct style of pizza (Factory Method) with the correct set of ingredients
(Abstract Factory)

Object-Oriented Programming 116


Abstract Factory Pattern Class Diagram of Abstract Factory Solution

Note:
Lots of classes not shown

Object-Oriented Programming 117


Abstract Factory Pattern Definition and Structure

▪ The Abstract Factory design pattern provides an interface for creating families of related or
dependent objects without specifying their concrete classes

Object-Oriented Programming 118


Abstract Factory Pattern Abstract Factory Characteristics

▪ Isolates concrete classes


▪ Makes exchanging product families easy
▪ Promotes consistency among products

Object-Oriented Programming 119


Design Patterns Template Method

Template Method Pattern

Object-Oriented Programming 120


Template Method Pattern Example: Tea and Coffee

▪ Consider an example in which we have recipes for making tea and coffee at a coffee shop

▪ Coffee
• Boil water
• Brew coffee in boiling water
• Pour coffee in cup
• Add sugar and milk

▪ Tea
• Boil water
• Steep tea in boiling water
• Pour tea in cup
• Add lemon

Object-Oriented Programming 121


Template Method Pattern Coffee class for making coffee

Coffee.java
1 public class Coffee {
2 void prepareRecipe() { Here’s our recipe for coffee, straight
3 boilWater(); out of the training manual.
4 brewCoffeeGrinds();
5 pourInCup();
6 addSugarAndMilk(); Each of the steps is implemented as
7 }
8 a separate method.
9 public void boilWater() {
10 System.out.println("Boiling water");
11 }
12
13 public void brewCoffeeGrinds() {
14 System.out.println("Dripping Coffee through filter"); Each of these methods implements
15 }
16 one step of the algorithm. There’s a
17 public void pourInCup() { method to boil water, brew the
18 System.out.println("Pouring into cup");
19 }
coffee, pour the coffee in a cup and
20 add sugar and milk.
21 public void addSugarAndMilk() {
22 System.out.println("Adding Sugar and Milk");
23 }
24 }

Object-Oriented Programming 122


Template Method Pattern Tea class for making tea

Tea.java
1 public class Tea {
2 void prepareRecipe() {
3 boilWater();
4 steepTeaBag(); This looks very similar to the one we
5 pourInCup(); just implemented in Coffee; the
6 addLemon(); second and forth steps are different,
7 }
8 but it’s basically the same recipe.
9 public void boilWater() {
10 System.out.println("Boiling water");
11 }
12
13 public void steepTeaBag() { Notice that these two methods
14 System.out.println("Steeping the tea"); These two are exactly the same as they
15 }
16 methods are are in Coffee! So we definitely
17 public void addLemon() { specialized to Tea. have some code duplication
18 System.out.println("Adding Lemon"); going on here.
19 }
20
21 public void pourInCup() {
22 System.out.println("Pouring into cup");
23 }
24 }

Object-Oriented Programming 123


Template Method Pattern Code Duplication!

▪ We have code duplication occurring in


these two classes
• boilWater() and pourInCup() are
exactly the same

▪ Lets get rid of the duplication

Object-Oriented Programming 124


Template Method Pattern Abstract classes Coffee, Tea

The prepareRecipe() method The boilWater() and pourInCup()


differs in each subclass, so it methods are shared by both subclasses,
is defined as abstract. so they are defined in the superclass.

Each subclass Each subclass overrides


implements its the prepareRecipe()
own recipe. method and implements
its own recipe.
The methods specific to
Coffee and Tea stay in the
subclasses.

Object-Oriented Programming 125


Template Method Pattern Similar algorithms

▪ The structure of the algorithms in prepareRecipe() is similar for Tea and Coffee
• We can improve our code further by making the code in prepareRecipe() more abstract
- brewCoffeeGrinds() and steepTea() -> brew()
- addSugarAndMilk() and addLemon() -> addCondiments()

▪ Now all we need to do is specify this structure in CaffeineBeverage.prepareRecipe()


and make sure we do it in such a way so that subclasses can’t change the structure
• By using the word “final”

Object-Oriented Programming 126


Template Method Pattern Tea class for making tea

CaffeineBeverage.java
1 public abstract class CaffeineBeverage {
2 Because Coffee and Tea handle these
3 final void prepareRecipe() {
4 boilWater(); methods in different ways, they’re going
5 brew(); to have to be declared as abstract. Let
6 pourInCup();
7 addCondiments(); the subclasses worry about that stuff!
8 }
9
10 abstract void brew();
11 abstract void addCondiments(); brew() and addCondiments() are
12 abstract and must be supplied by subclasses
13 void boilWater() {
14 System.out.println("Boiling water");
15 } boilWater() and pourInCup() are
16 specified and shared across all subclasses
17 void pourInCup() {
18 System.out.println("Pouring into cup");
19 }
20 }

Object-Oriented Programming 127


Template Method Pattern Dealing with the Coffee and Tea classes

Tea.java ▪ Tea and Coffee now extend


1 public class Tea extends CaffeineBeverage { CaffeineBeverage.
2 public void brew() {
3 System.out.println("Steeping the tea");
4 }
5 ▪ Tea needs to define brew() and
6 public void addCondiments() {
7 System.out.println("Adding Lemon"); addCondiments() — the two
8 } abstract methods from Beverage.
9 }

Coffee.java
▪ Same for Coffee, except Coffee
1 public class Coffee extends CaffeineBeverage {
2 public void brew() {
deals with coffee, and sugar and
3 System.out.println("Dripping Coffee through filter"); milk instead of tea bags and
4 }
5 lemon.
6 public void addCondiments() {
7 System.out.println("Adding Sugar and Milk");
8 }
9 }

Object-Oriented Programming 128


Template Method Pattern What have we done?

▪ Took two separate classes with separate but similar algorithms

▪ Noticed duplication and eliminated it by adding a superclass

▪ Made steps of algorithm more abstract and specified its structure in the superclass
• Thereby eliminating another “implicit” duplication between the two classes

▪ Revised subclasses to implement the abstract (unspecified) portions of the algorithm… in


a way that made sense for them

Object-Oriented Programming 129


Template Method Pattern Definition

▪ 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

• Template Method defines the steps of an algorithm and allows subclasses to provide the
implementation for one or more steps

- Makes the algorithm abstract


- Each step of the algorithm is represented by a method

- Encapsulates the details of most steps


- Steps (methods) handled by subclasses are declared abstract
- Shared steps (concrete methods) are placed in the same class that has the template method, allowing for code
re-use among the various subclasses

Object-Oriented Programming 130


Template Method Pattern Structure

The template method makes use of the


The AbstractClass contains primitiveOperations to implement an
the template method. algorithm. It is decoupled from the actual
implementation of these operations.
...and abstract versions of
the operations used in the
template method.

There may be many The ConcreteClass implements


ConcreteClasses, each the abstract operations, which
implementing the full are called when the
set of operations templateMethod() needs them.
required by the
template method.

Object-Oriented Programming 131


Design Patterns Singleton Pattern

Singleton Pattern

Object-Oriented Programming 132


Singleton Pattern Deriving Singleton (I)

▪ Let’s derive this Ball.java


pattern by 1 public class Ball {
starting with a 2 private String color;
class that has no 3
4 public Ball(String color) {
restrictions on 5 this.color = color; As long as a client object “knows about”
who can create it 6 } the name of class Ball, it can create
7 instances of Ball
8 public void bounce() {
9 System.out.println("Boing!"); This is because the constructor is public
10 }
11
12 public static void main(String[] args) {
13 Ball b1 = new Ball("Red");
14 Ball b2 = new Ball("Blue");
15 b1.bounce();
16 b2.bounce(); We can stop unauthorized
17 } creation of Ball instances by
18 }
making the constructor private

Object-Oriented Programming 133


Singleton Pattern Deriving Singleton (II)

Ball.java BallTestDrive.java
1 public class Ball { 1 public class BallTestDrive {
2 private String color; 2 public static void main(String[] args) {
3 3 Ball b1 = new Ball("Red");
4 private Ball(String color) { 4 }
5 this.color = color; 5 }
6 }
7
8 public void bounce() {
9 System.out.println("Boing!");
10 }
Now
11 } Ball b1 = new Ball("Red");
impossible by any method outside of Ball

Object-Oriented Programming 134


Singleton Pattern Problem: No Point of Access!

▪ Now that the constructor is private, no class can gain access to instances of Ball
• But our requirements were that there would be at least one way to get access to an instance of
Ball

▪ We need a method to return an instance of Ball


• But since there is no way to get access to an instance of Ball, the method CANNOT be an
instance method
- This means it needs to be a class method, aka a static method

Object-Oriented Programming 135


Singleton Pattern Deriving Singleton (III)

Ball.java BallTestDrive.java
1 public class Ball { 1 public class BallTestDrive {
2 private String color; 2
3 3 public static void main(String[] args) {
4 private Ball(String color) { 4 // Ball b1 = new Ball("Red");
5 this.color = color; 5 Ball b1 = Ball.getInstance("Blue");
6 } 6 }
7
7 }
8 public void bounce() {
9 System.out.println("Boing!");
10 }
11 We are back to this problem where any client
12 public static Ball getInstance(String color) { can create an instance of Ball;
13 return new Ball(color); instead of saying this:
14 } Ball b1 = new Ball("Red");
15
16 } they just say:
Ball b1 = Ball.getInstance("Blue");

Object-Oriented Programming 136


Singleton Pattern Deriving Singleton (IV)

Ball.java To ensure only one instance is ever created


1 public class Ball { ▪ Need a static variable to store that instance
2 private static Ball ball;
3 • No instance variables are available in static
4 private String color; methods
5
6 private Ball(String color) {
7 this.color = color;
8
Now the getInstance() method returns null
}
9 each time it is called
10 public void bounce() { ▪ Need to check the static variable to see if it is
11 System.out.println("Boing!");
12
null
}
13 • If so, create an instance
14 public static Ball getInstance(String color) {
15 return ball; ▪ Otherwise return the single instance
16 }
17 }

Object-Oriented Programming 137


Singleton Pattern Problem: First Parameter Wins

Ball.java ▪ The code shows the Singleton pattern


1 public class Ball {
2
• private constructor
private static Ball ball;
3 • private static variable to store the single
4 private String color;
5
instance
6 private Ball(String color) { • public static method to gain access to that
7 this.color = color;
8 }
instance
9
10
• this method creates object if needed;
public void bounce() {
11 System.out.println("Boing!"); returns it
12 }
13
14 public static Ball getInstance(String color) { ▪ But this code ignores the fact that a
15 if (ball == null) { parameter is being passed in;
16 ball = new Ball(color);
17 }
18 return ball; ▪ so if a “Red” ball is created all subsequent
19 } requests for a “Green” ball are ignored
20 }
Lazy instantiation

Object-Oriented Programming 138


Singleton Pattern Solution: Use a Map

▪ The solution to the final problem is to change the private static instance variable to a Map
private static Map<String, Ball> ballRecord = new HashMap...

▪ Then check if the map contains an instance for a given value of the parameter
• this ensures that only one ball of a given color is ever created
• this is a very acceptable variation of the Singleton pattern

Ball.java
1 public static Ball getInstance(String color) {
2 if (!ballRecord.containsKey(color)) {
3 ballRecord.put(color, new Ball(color));
4 }
5
6 return ballRecord.get(color);
7 }

Object-Oriented Programming 139


Singleton Pattern Definition

▪ Used to ensure that only one instance of a particular class ever gets created and that
there is just one (global) way to gain access to that instance

• What’s really going on here? We’re taking a class and letting it manage a single instance of itself.
We’re also preventing any other class from creating a new instance on its own. To get an
instance, you’ve got to go through the class itself.

• We’re also providing a global access point to the instance: whenever you need an instance, just
query the class and it will hand you back the single instance. We can implement this so that the
Singleton is created in a lazy manner, which is especially important for resource-intensive
objects.

Object-Oriented Programming 140


Singleton Pattern Structure

▪ Singleton involves only a single class (not typically called Singleton). That class is a full-
fledged class with other attributes and methods (not shown).

▪ The class has a static variable that points at a single instance of the class.

▪ The class has a private constructor (to prevent other code from instantiating the class)
and a static method that provides access to the single instance.

Object-Oriented Programming 141


Singleton Pattern Singleton Pattern: Real World Examples

▪ Centralized manager of resources


• Window manager
• File system manager
• …

▪ Logger classes

▪ Factories
• Especially those that issue IDs
• Singleton is often combined with Factory Method and Abstract Factory patterns

Object-Oriented Programming 142


Design Patterns Decorator Pattern

Decorator Pattern

Object-Oriented Programming 143


Decorator Pattern Decorator Pattern

▪ The Decorator Pattern provides a powerful mechanism for adding new behaviors to an
object at run-time

• The mechanism is based on the notion of “wrapping” which is just a fancy way of saying “delegation” but
with the added twist that the delegator and the delegate both implement the same interface

- You start with object A that implements interface C


- You then create object B that also implements interface C
- You pass A into B’s constructor and then pass B to A’s client
- The client thinks its talking to A (via C’s interface) but its actually talking to B
- B’s methods augment A’s methods to provide new behavior

Object-Oriented Programming 144


Decorator Pattern Why? Open-Closed Principle

▪ The decorator pattern provides yet another way in which a class’s runtime behavior can
be extended without requiring modification to the class

▪ This supports the goal of the open-closed principle:


• Classes should be open for extension but closed to modification

- Inheritance is one way to do this, but composition and delegation are more flexible (and Decorator takes
advantage of delegation)

- As the Gang of Four put it: “Decorator lets you attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending functionality.”

• Our “Starbuzz Coffee” example, taken from Head First Design Patterns, clearly demonstrates why
inheritance can get you into trouble and why delegation/composition provides greater run-time flexibility

Object-Oriented Programming 145


Decorator Pattern Starbuzz Coffee

▪ Under pressure to update their “point of sale” system to keep up with their expanding set
of beverage products

• Started with a Beverage abstract base class and four implementations: HouseBlend, DarkRoast, Decaf,
and Espresso
- Each beverage can provide a description and compute its cost

• But they also offer a range of condiments including: steamed milk, soy, and mocha

- These condiments alter a beverage’s description and cost

- The use of the word “Alter” here is key since it provides a hint that we might be able to use the Decorator pattern

Object-Oriented Programming 146


Decorator Pattern Initial Starbuzz System

▪ With inheritance on your brain, you may add condiments to this design in one of two ways
1. One subclass per combination of condiment (wont work in general but especially not in Boulder!)
2. Add condiment handling to the Beverage superclass

Object-Oriented Programming 147


Decorator Pattern Approach One: One Subclass per Combination

▪ This is incomplete, but you can see the problem…

Object-Oriented Programming 148


Decorator Pattern Approach Two: Let Beverage Handle Condiments

Houston, we have a problem…

1. This assumes that all concrete


Beverage classes need these
condiments
2. Condiments may vary (old ones
go, new ones are added, price
changes occur, etc.), shouldn’t
Beverage be encapsulated from
this some how?
3. How do you handle “double
soy” drinks with boolean
variables?

Object-Oriented Programming 149


Decorator Pattern Decorator Pattern: Definition and Structure

Inheritance is used to make sure


that components and decorators
share the same interface: namely
the public interface of Component
which is either an abstract class or
an interface

Each decorator is
cohesive, focusing
just on its added
functionality
▪ At run-time, concrete decorators wrap
concrete components and/or other
concrete decorators

▪ The object to be wrapped is typically


passed in via the constructor

Object-Oriented Programming 150


Decorator Pattern Client Perspective

▪ In both situations, Client thinks its


talking to a Component. It shouldn’t
know about the concrete subclasses.

Object-Oriented Programming 151


Decorator Pattern StarBuzz Using Decorators

Beverage acts as
our abstract
component class.
Here's the reference to the
Beverage that the
Decorators will be rapping.

And here are our condiment


decorators; notice they need
to implement not only cost()
but also getDescription(). We’ll
see why in a moment...

The four concrete


components, one
per coffee type.

Object-Oriented Programming 152


Decorator Pattern Real-World Decorators: Java I/O

Here’s our abstract component.

FilterInputStream is an
abstract decorator.

These InputStreams act as the


concrete components that we
And finally, here are all our
will wrap with decorators. There
concrete decorators.
are a few more we didn’t show,
like ObjectInputStream.

Object-Oriented Programming 153


Decorator Pattern The Textbook’s Take

▪ As we saw, Decorator offers another solution to the problem of rapidly multiplying combinations
of subclasses
• we saw examples of other solutions when we made use of the strategy pattern and the bridge pattern

▪ The decorator pattern provides a means for creating different combinations of functionality by
creating chains in which each member of the chain can augment or “decorate” the output of the
previous member
• Plus, it separates the step of building these chains from the use of these chains

▪ The Decorator pattern comes into play when there are a variety of optional functions that can
precede or follow another function that is always executed

▪ This is a very powerful idea that can be implemented in a variety of ways.


• The fact that all of the classes in the decorator pattern hide behind the abstraction of Component enables
all of the good benefits of OO design discussed previously

Object-Oriented Programming 154


Decorator Pattern The Textbook’s Take (II)

▪ As we saw, Decorator offers another solution to the problem of rapidly multiplying


combinations of subclasses
• we saw examples of other solutions when we made use of the strategy pattern and the bridge
pattern

▪ The decorator pattern provides a means for creating different combinations of


functionality by creating chains in which each member of the chain can augment or
“decorate” the output of the previous member

• Plus, it separates the step of building these chains from the use of these chains

Object-Oriented Programming 155


Design Patterns More Information on Design Patterns…

▪ Patterns
• http://en.wikipedia.org/wiki/Software_pattern
• https://sourcemaking.com/design_patterns
• http://hillside.net/patterns/patterns-catalog
• http://c2.com/ppr/

▪ Interaction design patterns


• http://en.wikipedia.org/wiki/Interaction_design_pattern

▪ Anti-Patterns
• http://en.wikipedia.org/wiki/Anti-pattern#Programming_anti-patterns

Object-Oriented Programming 156


Thank you!

Object-Oriented Programming 157

You might also like