0% found this document useful (0 votes)
149 views30 pages

Lecture 5&6

O.s lectures for cs students.

Uploaded by

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

Lecture 5&6

O.s lectures for cs students.

Uploaded by

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

CS#7250(Design(Patterns(and

Refactoring

Instructor:(Awais(Qasim
The$Decorator$Pattern
Example:)StarBuzz)Coffee

Starbuzz coffee sells different beverages.


The cost of each beverage is calculated differently.

The beverages sold by Starbuzz are HouseBlend,


DarkRoast, Decaf and Espresso.

Starbuzz needs a system to calculate the cost for each


beverage when purchases are made.
!
Class%Diagram

BEVERAGE
description

get_description()
cost()

HOUSE_BLEND DARK_ROAST DECAF ESPRESSO


cost() cost() cost() cost()
Revisions(to(System
In addition to standard coffee a customer can ask for
several condiments such as steamed milk, soy, and
mocha and have it all topped off with whipped milk.

Starbuzz charges a bit for each of these, so they require


them to be built into their order system.
Extensions)to)the)Class)Diagram
Problems)with)this)approach
Too many subclasses may be needed.

Need to define the implementation of each subclass.

All classes inherit a static behaviour which may have to be


overridden.

The inherited behaviour cannot be changed at runtime, i.e.


behaviour is static at runtime.

Thus, the design is not flexible or maintainable.


!
What happens when the price of milk goes up?

What do they do when they add a new caramel topping?

Cant we just use instance variables and inheritance


in the superclass to keep track of the condiments?
Another(Option
Problems)with)this)approach
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().
Problems)with)using)inheritance)approach
We get class explosions, rigid designs, or we add
functionality to the base class that isnt appropriate for
some of the subclasses.
Design'Principle
In order to maintain code we should aim at adding new
functionality by adding new code rather than changing
existing code.

Design principle: classes should be open for extension


but closed for modification.

In this way the chances of introducing bugs or causing


unintended side effects are reduced.
Only apply this to areas that are most likely to change.

Due to the tradeoffs the decorator pattern should not


be used throughout the design but in areas that are
most likely to change.
!
Applying(Decorators(to(the(Starbuzz(Example
Well start with a beverage and decorate it with the
condiments at runtime.

If the customer wants a Dark Roast with Mocha and


Whip, then well:
Order:&Dark&Roast&with&Mocha&and&Whip
Important)Points)about)Decorators
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.
Decorator(Pattern

Provides a flexible alternative to using inheritance to extend


functionality.

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.


!
Class%Diagram%for%the%Decorator%Pattern

Component
methodA()
methodB()
//other methods
component

ConcreteComponent Decorator
methodA() methodA()
methodB() methodB()
//other methods //other methods

ConcreteDecoratorA ConcreteDecoratorB
Component wrapped Object Component wrapped Object
Object newState
methodA()
methodB()
newBehavior() methodA()
//other methods methodB()
//other methods
Starbuzz(Coffee(Example

Beverage
description

getDescription()
cost()
//other methods
component

CondimentDecorator
HouseBlend DarkRoast Espresso Decaf getDescription()
cost() cost() cost() cost()

Milk Mocha Soy


Beverage beverage Beverage beverage Beverage beverage
getDescription() getDescription() getDescription()
cost() cost() cost()
Writing'the'Starbuzz'code
public abstract class Beverage {
String description = Unknown Beverage;
public String getDescription() {
return description;
}
public abstract double cost();
}

public abstract class CondimentDecorator extends Beverage{


public abstract String getDescription();
}
Writing'the'Starbuzz'code
public class Espresso extends Beverage {
public Espresso() {
description = Espresso;
}
public double cost() {
return 1.99;
}
}

public class HouseBlend extends Beverage {


public HouseBlend() {
description = House Blend Coffee;
}
public double cost() {
return .89;
}
Writing'the'Starbuzz'code
public class DarkRoast extends Beverage {
public Espresso() {
description = Espresso;
}
public double cost() {
return 0.99;
}
}

public class Decaf extends Beverage {


public HouseBlend() {
description = House Blend Coffee;
}
public double cost() {
return 1.05;
}
Writing'the'Starbuzz'code
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {


return beverage.getDescription() + , Mocha;
}

public double cost() {


return .20 + beverage.cost();
}
}
Writing'the'Starbuzz'code

Write and compile the code for the other Soy and Whip
condiments. Youll need them to finish and test the
application.
Writing'the'Starbuzz'code
Output
The$Decorator$Pattern
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 after the delegation.

Objects can be delegated dynamically at runtime.

The objects are wrapped with decorators.


!!!Java!IO!API!and!the!Decorator!Pattern
Decorator(Pattern(Overview
Adds flexibility to designs.

Results in a number of small classes being added


to the design which makes the project more
complicated.

The decorators are a set of wrappers around an


object of an abstract class or interface.

Code maybe dependant on specific types and


introducing decorators can lead to unexpected
side effects.

Code needed to instantiate the component can be


complex as a number of decorators have to be
wrapped around the object.
Parting(Exercise
Our friends at Starbuzz have introduced sizes to their menu.
You can now order a coffee in tall, grande, and venti
sizes (translation: small, medium, and large).

Starbuzz saw this as an intrinsic part of the coffee class, so


theyve added two methods to the Beverage class:
setSize() and getSize().

Theyd also like for the condiments to be charged according


to size, so for instance, Soy costs 10, 15 and 20
respectively for tall, grande, and venti coffees.

How would you alter the decorator classes to handle this


change in requirements?
Exercise(Solution

You might also like