Sei sulla pagina 1di 20

Decorating Objects (The Decorator Pattern)

Luca Vigan
Dipartimento di Informatica Universit di Verona

Laboratorio di Ingegneria del Software 06.05.2011

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

1 / 20

Decorating Classes

Youll learn how to decorate your classes at runtime using a form of object composition. Why? Once you know the techniques of decorating, youll be able to give your (or someone elses) objects new responsibilities without making any code changes to the underlying classes.

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

2 / 20

A Problem Description: Welcome to Starbuzz Coffee


Starbuzz Coffee has made a name for itself as the fastest growing coffee shop around. If youve seen one on your local corner, look across the street: youll see another one. Because theyve grown so quickly, theyre scrambling to update their ordering systems to match their beverage offerings. When they rst went into business they designed their classes like this...

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

3 / 20

Welcome to Starbuzz Coffee (2)


In addition to your coffee, you can also ask for several condiments like steamed milk, soy, and mocha, and have it all topped off with whipped milk. Starbuzz charges a bit for each of these, so they really need to get them built into their order system. Heres their rst attempt....

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

4 / 20

Think!

Its pretty obvious that Starbuzz has created a maintenance nightmare for themselves.
What happens when the price of milk goes up? What do they do when they add a new caramel topping? Thinking beyond the maintenance problem, which of the design principles that weve covered so far are they violating?

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

5 / 20

A possible solution?
Why do we need all these classes? Cant we just use instance variables and inheritance in the superclass to keep track of the condiments?

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

6 / 20

A possible solution?
Lets add in the subclasses, one for each beverage on the menu:

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

7 / 20

Brain Teaser

Write the cost() methods for the following classes:


public class Beverage { public double c o s t ( ) { } } public class DarkRoast extends Beverage { public DarkRoast ( ) { d e s c r i p t i o n = " M o s t E x c e l l e n t Dark Roast " ; } public double c o s t ( ) { } }

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

8 / 20

Problems?

What requirements or other factors might change that will impact this design?
Price changes for condiments will force us to alter existing code. New condiments will force us to add new methods and alter the cost method in the superclass. We may have new beverages. For some of these beverages (iced tea?), the condiments may not be appropriate, yet the Tea subclass will still inherit methods like hasWhip(). (remember Strategy?) What if a customer wants a double mocha?

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

9 / 20

The Open-Closed Principle

Design Principle Classes should be open for extension, but closed for modication. Feel free to extend classes with any new behavior you like. If your needs or requirements change (and we know they will), just go ahead and make your own extensions. But we spent a lot of time getting this code correct and bug free, so we cant let you alter the existing code. It must remain closed to modication.

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

10 / 20

Meet the Decorator Pattern

Well start with a beverage and decorate it with the condiments at runtime. For example if the customer wants a Dark Roast with Mocha and Whip, then well:
1) 2) 3) 4) Take a DarkRoast object Decorate it with a Mocha object Decorate it with a Whip object Call the cost() method and rely on delegation to add on the condiment costs

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

11 / 20

Constructing a drink order with Decorators

1) Take a DarkRoast object

Remember hat DarkRoast inherits from Beverage and has a cost() method that computes the cost of the drink.

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

12 / 20

Constructing a drink order with Decorators (2)


2) The customer wants Mocha, so we create a Mocha object and wrap it around the DarkRoast

The Mocha object is a decorator: its type mirrors (i.e. it is the same type) the object it is decorating, in this case, a Beverage. So, Mocha has a cost() method too, and through polymorphism we can treat any Beverage wrapped in Mocha as a Beverage, too (because Mocha is a subtype of Beverage).

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

13 / 20

Constructing a drink order with Decorators (3)


3) The customer also wants Whip, so we create a Whip decorator and wrap Mocha with it

Whip is a decorator, so it also mirrors DarkRoasts type and includes a cost() method. So, a DarkRoast() wrapped in Mocha and Whip is still a Beverage and we can do anything with it we can do with a DarkRoast, including call its cost() method.

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

14 / 20

Constructing a drink order with Decorator (4)


4) Now its time to compute the cost for the customer. We do this by calling cost() on the outermost decorator, Whip, and Whip is going to delegate computing the cost to the objects it decorates. Once it gets a cost, it will add on the cost of the Whip

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

15 / 20

Constructing a drink order with Decorator (5)

First, we call cost() on the outmost decorator, Whip. Whip calls cost() on Mocha. Mocha calls cost() on DarkRoast. DarkRoast returns its cost: 99 cents. Mocha adds its cost, 20 cents, to the result from DarkRoast, and returns the new total: $ 1.19. Whip adds its total, 10 cents, to the result from Mocha, and returns the nal result: $ 1.29.
Luca Vigan (Universit di Verona) Decorator Lab. Ing. del SW, 06.05.2011 16 / 20

The Decorator Pattern


Decorators have the same supertype as the objects 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 (wrapped) object. The decorator adds its own behavior either before and/or after delegating to the object it decorates to do the rest of the job. Objects can be decorated at any time, so we can decorate objects dynamically at runtime with as many decorators as we like. The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a exible alternative to subclassing for extending functionality.
Luca Vigan (Universit di Verona) Decorator Lab. Ing. del SW, 06.05.2011 17 / 20

Decorator Uml Diagram:

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

18 / 20

Decorating our Beverages


Lets work our Starbuzz beverages into this framework...

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

19 / 20

Summary the Starbuzz code

OO Principles
Encapsulate what varies Favor composition over inheritance Program to interfaces, not implementations Strive for loosely coupled designs between objects that interact Classes should be open for extension but closed for modication

Its time to turn this design into some real Starbuzz code!

Luca Vigan (Universit di Verona)

Decorator

Lab. Ing. del SW, 06.05.2011

20 / 20

Potrebbero piacerti anche