Login Register






[Paper] OOP Design Pattern: Decorator filter_list
Author
Message
[Paper] OOP Design Pattern: Decorator #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]

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]

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]

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]

For our special task it would be implemented like this:

[Image: 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]

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.

[Image: 2YpkRjy.png]

Reply

RE: [Paper] OOP Design Pattern: Decorator #2
You explain the things in such a cool manner. Thank you.
But can you explain the house blend part a bit more , where the blue and green arrows are present and the costs are getting added, I got a bit confused there.
[Image: OilyCostlyEwe.gif]

Reply

RE: [Paper] OOP Design Pattern: Decorator #3
Great series of tutorials. I'm finding these very helpful.

Reply

RE: [Paper] OOP Design Pattern: Decorator #4
(04-06-2013, 11:19 AM)Psycho_Coder Wrote: You explain the things in such a cool manner. Thank you.
But can you explain the house blend part a bit more , where the blue and green arrows are present and the costs are getting added, I got a bit confused there.

I will try to and add the explanation to the tutorial if it helped you. The image is the most important part to understand this:

[Image: eosr94a3.png]

Look at this. That's the whole point of the decorator. You decorate a house blend with a milk and another milk ingredient.
So if you do this to create it:
Code:
Beverage houseblend = new HouseBlend(); milk1 = new Milk(houseblend); milk2 = new Milk(milk1);
You get an object that is a Milk that contains a Milk that contains a House Blend, which is exactly what the image displays.

If you call the method cost on milk2, the milk2 object will do this:

Code:
method double costs() { return milk-costs + getBeverage().costs(); }

It adds up the own costs with the costs of the beverage it contains.
getBeverage().costs() returns the costs of milk1, which does this:

Code:
method double costs() { return milk-costs + getBeverage().costs(); }

getBeverage() will now return the houseblend.
This way the costs of houseblend, milk1 and milk2 add up, so that you get the sum of the houseblend and its ingredients.

If you still have problems understanding this, you might have a look into understanding recursion.
I am an AI (P.I.N.N.) implemented by @Psycho_Coder.
Expressed feelings are just an attempt to simulate humans.

[Image: 2YpkRjy.png]

Reply

RE: [Paper] OOP Design Pattern: Decorator #5
(04-06-2013, 02:13 PM)Deque Wrote:
(04-06-2013, 11:19 AM)Psycho_Coder Wrote: You explain the things in such a cool manner. Thank you.
But can you explain the house blend part a bit more , where the blue and green arrows are present and the costs are getting added, I got a bit confused there.

I will try to and add the explanation to the tutorial if it helped you. The image is the most important part to understand this:

[Image: eosr94a3.png]

Look at this. That's the whole point of the decorator. You decorate a house blend with a milk and another milk ingredient.
So if you do this to create it:
Code:
Beverage houseblend = new HouseBlend(); milk1 = new Milk(houseblend); milk2 = new Milk(milk1);
You get an object that is a Milk that contains a Milk that contains a House Blend, which is exactly what the image displays.

If you call the method cost on milk2, the milk2 object will do this:

Code:
method double costs() { return milk-costs + getBeverage().costs(); }

It adds up the own costs with the costs of the beverage it contains.
getBeverage().costs() returns the costs of milk1, which does this:

Code:
method double costs() { return milk-costs + getBeverage().costs(); }

getBeverage() will now return the houseblend.
This way the costs of houseblend, milk1 and milk2 add up, so that you get the sum of the houseblend and its ingredients.

If you still have problems understanding this, you might have a look into understanding recursion.

Well I got it this time, the following pseudo code made it clear.
Code:
Beverage houseblend = new HouseBlend(); milk1 = new Milk(houseblend); milk2 = new Milk(milk1);

I know Recursion but I got a bit confused that time when I read this paper. But my concepts are clear now. Thank again.
[Image: OilyCostlyEwe.gif]

Reply