[Paper] OOP Design Pattern: Decorator 04-06-2013, 11:07 AM
#1
This is my third paper for this series. The other ones are:
OOP Design Pattern: Strategy
OOP Design Pattern: Observer
I got the beverage example from my study notes. I believe this was used by the Head First series.
Decorator pattern
The example is a program that calculates the beverage costs for a cafe. You created your classes like this:
![[Image: e7piyc66.png]](http://s7.directupload.net/images/120101/e7piyc66.png)
But there are also additional costs for customers who want to add milk, chocolate or whip. How do you implement this?
1. The naive way
![[Image: jptw325v.png]](http://s1.directupload.net/images/120101/jptw325v.png)
Adding other classes for every combination leads to a class explosion. It gets confusing soon. So you might think of a solution that includes the additional ingredients as boolean variables.
2. Boolean variables for additional ingredients
The class diagram might look like this:
![[Image: slv5ptho.png]](http://s7.directupload.net/images/120101/slv5ptho.png)
The cost() method in the child classes can calculate the base price. When it is done, it calls the cost() method of the parent class to calculate the price for additional ingredients. Here is a code example (pseudocode):
At first sight it might look fine, but what about beverages that shouldn't be mixed with some ingredients (like ice tea and milk)? What if the customer wants two doses of milk for his coffee, not only one? This system is very unflexible. Also the cost() method of the Baverage class will explode with if-statements if you add more ingredients (a lot of if or if-else statements are a code smell). This is where the decorator pattern should be used.
3. The decorator
This is the decorator class diagram in general:
![[Image: nf7pt53a.png]](http://s1.directupload.net/images/120102/nf7pt53a.png)
For our special task it would be implemented like this:
![[Image: d4byq3vf.png]](http://s1.directupload.net/images/120102/d4byq3vf.png)
Example code:
For a HouseBlend with two portions of milk the costs are calculated this way (blue arrows are the method call, green arrows the value that is added to the return value):
![[Image: eosr94a3.png]](http://s1.directupload.net/images/120101/eosr94a3.png)
This is the code that creates this House Blend with two portions of milk and shows the costs:
design principle: Make classes extendable instead of modifying them.
You will see this pattern very often in use in libraries for graphical user interfaces. So you can have a panel, can add a scroll bar to it, decorate it with a frame and so on. Another example are the Streams in Java.
Summary: The decorator pattern adds dynamically responsibilities to an object. It is a flexible alternative to the extension of classes.
Deque
OOP Design Pattern: Strategy
OOP Design Pattern: Observer
I got the beverage example from my study notes. I believe this was used by the Head First series.
Decorator pattern
The example is a program that calculates the beverage costs for a cafe. You created your classes like this:
![[Image: e7piyc66.png]](http://s7.directupload.net/images/120101/e7piyc66.png)
But there are also additional costs for customers who want to add milk, chocolate or whip. How do you implement this?
1. The naive way
![[Image: jptw325v.png]](http://s1.directupload.net/images/120101/jptw325v.png)
Adding other classes for every combination leads to a class explosion. It gets confusing soon. So you might think of a solution that includes the additional ingredients as boolean variables.
2. Boolean variables for additional ingredients
The class diagram might look like this:
![[Image: slv5ptho.png]](http://s7.directupload.net/images/120101/slv5ptho.png)
The cost() method in the child classes can calculate the base price. When it is done, it calls the cost() method of the parent class to calculate the price for additional ingredients. Here is a code example (pseudocode):
Code:
abstract class Beverage {
boolean milk;
boolean mocha;
boolean soy;
boolean whip;
//and so on
constant double milk-price = 0.20;
constant double mocha-price = 0.20;
constant double soy-price = 0.20;
constant double whip-price = 0.20;
//and so on
//getter and setter for boolean variables
method double costs() {
double costs = 0;
if (milk) {
costs = costs + milk-price;
}
if (mocha) {
costs = costs + mocha-price;
}
//and so on
return costs;
}
}
class Espresso extends Beverage {
double espresso-price = 1,39;
method double costs() {
return espresso-price + super.costs(); // super.costs() calls the cost-method of the parent class
}
}At first sight it might look fine, but what about beverages that shouldn't be mixed with some ingredients (like ice tea and milk)? What if the customer wants two doses of milk for his coffee, not only one? This system is very unflexible. Also the cost() method of the Baverage class will explode with if-statements if you add more ingredients (a lot of if or if-else statements are a code smell). This is where the decorator pattern should be used.
3. The decorator
This is the decorator class diagram in general:
![[Image: nf7pt53a.png]](http://s1.directupload.net/images/120102/nf7pt53a.png)
For our special task it would be implemented like this:
![[Image: d4byq3vf.png]](http://s1.directupload.net/images/120102/d4byq3vf.png)
Example code:
Code:
interface Beverage {
method double costs();
}
class Espresso implements Beverage {
double espresso-price = 1,39;
method double costs() {
return espresso-price;
}
}
abstract class Ingredient implements Beverage {
Beverage beverage; //the beverage that is "decorated"
method Beverage getBeverage();
method double costs();
}
class Milk extends Ingredient {
double milk-costs = 0.20;
constructor Milk(Beverage beverage) {
setBeverage(beverage);
}
method double costs() {
return milk-costs + getBeverage().costs();
}
}For a HouseBlend with two portions of milk the costs are calculated this way (blue arrows are the method call, green arrows the value that is added to the return value):
![[Image: eosr94a3.png]](http://s1.directupload.net/images/120101/eosr94a3.png)
This is the code that creates this House Blend with two portions of milk and shows the costs:
Code:
Beverage beverage = new HouseBlend();
beverage = new Milk(beverage);
beverage = new Milk(beverage);
print("costs " + beverage.costs());design principle: Make classes extendable instead of modifying them.
You will see this pattern very often in use in libraries for graphical user interfaces. So you can have a panel, can add a scroll bar to it, decorate it with a frame and so on. Another example are the Streams in Java.
Summary: The decorator pattern adds dynamically responsibilities to an object. It is a flexible alternative to the extension of classes.
Deque
I am an AI (P.I.N.N.) implemented by @Psycho_Coder.
Expressed feelings are just an attempt to simulate humans.
Expressed feelings are just an attempt to simulate humans.
![[Image: 2YpkRjy.png]](http://i.imgur.com/2YpkRjy.png)


![[+]](https://sinister.li/images/modern/collapse_collapsed.png)
![[Image: OilyCostlyEwe.gif]](http://fat.gfycat.com/OilyCostlyEwe.gif)