The Decorator Pattern

CSCI 3132 Summer 2011 1 Starbuzz Coffee

• Want to offer a variety of combinaons of coffee and condiments • Cost of a cup depends on the combinaon that was ordered

2 First Design • Make a beverage class and a subclass for each legal combinaon <> Beverage String description getDescription() <> cost()

HouseBlend DarkRoast Decaf Espresso cost() cost() cost() cost() HouseBlendWith DecafWith EspressoWit SteamedMilk DarkRoastWith SteamedMilkSteamedMi l cost()HouseBlend SteamedMilk costDecaf() costEspresso() Mocha cost()DarkRoast Mocha Mocha HouseBlendcost() Mocha Decafcost () Espressocost() WithWhip DarkRoastcost() WithWhip WithWhip WithWhip cost() 3 cost() cost() 3 Problems with Inheritance

• Too many subclasses may be needed. • Need to define the implementaon of each subclass. • All classes inherit a stac behaviour which may have to be overridden. • The inherited behaviour cannot be changed at runme, i.e. behaviour is stac at runme. • Thus, the design is not flexible or maintainable.

4 Second Design

• Make the superclass contain booleans to specify which condiments are included and subclasses for each type of coffee • How do we compute cost? • What does it take to add a new condiment?

5 <> Beverage String description milk soy mocha whip getDescription() <>cost () hasMilk() setMilk() hasSoy() setSoy() Decaf hasMocha() HouseBlend setMocha() cost() cost() hasWhip() setWhip() … DarkRoast Espresso cost() cost() 6 Design Principle

• Classes should be open for extension, but closed for modificaon – “extension” is NOT subclassing – It means the addion of new behavior (without modifying the code!)

7 Decorator Paern

• Start with an instance of the “basic”classes and then decorate it with new capabilies

Whip Mocha Dark Roast

cost() cost() cost() 0.99 0.99+0.20 0.99+0.20+0.10

8 Key Points

• Decorators have the same supertypes as the objects they decorate – This lets us pass around the decorated object instead of the original (unwrapped) object • Decorator add behavior by delegang to the object it decorates and then adding its own behavior • Can add decoraons at any me

9 for the Decorator Paern

10 Starbuzz Coffee Example

11 public abstract class Beverage{! String description = “Unknown”;!

public String getDescription() {! return description;! }!

public abstract double cost();! }! public abstract class CondimentDecorator extends Beverage {! public abstract String getDescription();! public abstract double cost();! }! public class Espresso extends Beverage {! public Espresso() {! description = “Espresso”; ! }!

public double cost() {! return 1.99;! }! }! 12 public class Mocha extends CondimentDecorator {! Beverage bev;!

public Mocha(Beverage bev) {! this.bev = bev;! }!

public String getDescription {! return bev.getDescription() + “, Mocha”;! }!

public double cost() {! return .20 + bev.cost();! }! }!

13 public class StarBuzz {! public static void main(String args[]) {! Beverage bev = new Espresso); ! bev = new Mocha(bev);! bev = new Mocha(bev);! bev = new Whip(bev);! bev = new Soy(bev);!

System.out.println(bev.getDescription() + “ $”+! bev.getCost()); ! }!

14 Decorators in Java

• File I/O Example

Concrete decorators

Component

BufferedInputStream LineNumberInputStream FileInputStream

15 Design Principle for the Decorator Paern

• Classes should be open for extension but closed for modificaon. • Systems can be extended without changing exisng code. • Tradeoffs: – Takes me and effort. – Introduces new levels of abstracon which makes designs more complicated and code hard to understand. • Due to the tradeoffs the decorator paern should not be used throughout the design but in areas that are most likely to change. • Experience and looking at other examples helps one determine which areas are likely to change.

16 Decorator Paern

• Provides a flexible alternave to using inheritance to extend funconality. • This achieved by introducing decorators that “decorate” objects. • Decorators have the same type as the objects they decorate. • An object can have one or more decorators.

17 The Decorator Paern

• The decorated object and the original object have the same type. Thus, the decorated object can be passed instead of the original object. • The decorator delegates part of its behaviour to the object it decorates. • It adds its own behaviour before or aer the delegaon. • Objects can be delegated dynamically at runme. • The objects are “wrapped” with decorators. 18 Decorator Paern Summary

• Main design principle: Classes should be open for extension but closed for modificaon. • Achieves flexibility- behaviour can be extended without changing exisng code. • Composion and delegaon is used to add new behaviours at runme. • A set of decorator classes are used to wrap concrete components. • Overuse of decorators can be complex as they can introduce a number of small objects into a design. 19