-J2EE Developer at Turkiye Is Bankası Core Banking Exchange project -Java-Flex Developer in TAV IT. Built softwares for several international airport (istanbul, ankara, izmir, tblisi, batumi, emfidha) with JPA/Spring/CXF/BlazeDS on server side and Flex on rich clients. -JavaEE&Process Project Laader at HSBC. -Presenter at Eclipsist 2008, on Rapid Rich Internet Application Development. Murat has posted 8 posts at DZone. View Full User Profile

Design Patterns Revisited - Decorator Pattern, Decorating your software

07.30.2008
| 12252 views |
  • submit to reddit

Here is a real life story; Years ago one of my colleagues and I developed a piece of software for order and payment management of restaurants. That time we did not know about how this process works, so we just role-played as a waiter, a restaurant owner and a customer. We made an assumption that a product's price is immutable if any change differenciates the price this should be a new product (like cheese added hamburger is cheeseburger). The changes which don't effect the price are stored as String field. In time, some restaurants started asking for products which can have extras, like pizza but with extra cheese. We kindly asked them to create new products from the admin console for those extras which change the price of the product. Where we failed was that we thought if the price changes there is no harm to create that as a new product, but imagine a pizza with combination of 20 different ingredients. Years after it is so easy to see why what we had failed. We needed to decorate the products instead of just adding a detailed text which can't update the price (just like we did).

The Decorator pattern is very easy to understand, use and implement. Lets imagine we have a car factory and we offer a variety of options to our customers - sunroof, airconditioner, airbags etc. First of all we need create our Car object. To make it simple I will be demonstrating a concrete car object but the best use should be creating a Car interface and build your Car objects implementing this interface.


public class FamilyCar{
private String description="This is family version 5 door";
private double price=10;
public String getDescription(){
return description;
}

public double getPrice(){
return price;
}
}

So far so good, but as our car hits the stores, customers would like options like sunroofs, extra airbags, child seat, a/c and we can't give those away for free. So lets create a decorator, again for ease of understanding I am creating a concrete decorator class, but in real life we should do that via interfaces for extensibility.

 

public class Sunroof{
private FamilyCar familyCar;
public Sunroof(FamilyCar familyCar){
this.familyCar=familyCar;
}
public String getDescription(){
return familyCar.getDescription()+" with sunroof";
}
public double getPrice(){
return familyCar.getPrice()+(familyCar.getPrice()*0.1);
}
}

So simply, if you want to sell a family car with sunroof, you can create a family car object and decorate it with sunroof, thats it. You may have noticed right now we can't handle to sell a car with sunroof and airbag (imagine we also have an airbag decorator) which is not good. So lets change our implementation...


public class FamilyCar implements Car{

...

public class Sunroof implements Car{

private Car car;

...

public class Airbag implements Car{

private Car car;

...

Now you can create a family car decorated with sunroof and airbag and the price will be calculated automatically.

new Airbag(new Sunroof(new FamilyCar())).getPrice();

 

You may have different interfaces for your Car and Option decorators and let your decorator interface extend your Car interface so you would have seperate implementations. Either way you choose, you will have vast variety of options to decorate your car and you will be the most extensible car dealer who can offer any price for any options wanted by their customers. Not bad? Let's burn some rubber and do not hesitate to use the decorators whenever you think they might work...

I really recommend you to read chapter 3 on Head First Design Patterns which I think has the best example for the topic.

Published at DZone with permission of its author, Murat Yener.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Andy Leung replied on Wed, 2008/07/30 - 8:23am

Great work!

But if you could provide example as solution to your introduction, it would be much easier for people to catch the idea.

Just my 2 cents.  ;)

Murat Yener replied on Wed, 2008/07/30 - 9:56am in response to: Andy Leung

If you read Head First Design Patterns, you would have already realised that my "real life" introduction is the food version of the beverage example in the book. So I just don't want to clone that example and changed the topic. But still you may just change car with a food name and any of accesories with the sizes and options of the meal.

instead of FamilyCar

public class Meatball{
private String description="normal meatball";
private double price=10;
public String getDescription(){
return description;
}

public double getPrice(){
return price;
}
}

 

and instead of  Sunroof

public class BarbequeSauce{  
private Meatball meatball;
public Meatball(Meatball meatball){
this.meatball=meatball;
}
public String getDescription(){
return meatball.getDescription()+" with sauce";
}
public double getPrice(){
return meatball.getPrice()+(meatball.getPrice()*0.1);
}
}

 

 

 and our interface part is;
public class Meatball implements Food{  

...
public class BarbequeSauce implements Food{  

private Food food;

...

Ali Anwar replied on Wed, 2008/07/30 - 1:47pm

The example was really good in explaining the theory of the pattern in a way that everybody can understand (and I read HFP book too), but, I still can't get how this can be practical. 

I'm not saying that decorative pattern is not practical, but for the restaurant example above, I would take totally different approach, since a pizza is still a pizza regardless of the extras it has, I prefer adding a set in it (Product class) with all these Extra class objects (that has a description, quantity and unit price), and the total would be the price of the pizza with the sum of the extras prices in that set.

The real problem is that I can't find a practical application for decorative pattern, unless I'm writing a product that will handle only pizza sales and I can predict (by client feedback) all the extras that can come with it, I can use this pattern, and then if the client changes his mind and wants a new type of extra (which they always do) to be added to the application. the trouble and work required is too much for a simple task like this. (again I'm not discussing the example above, I'm using it to show my point)

Where can we find ourselves really in need for decorative use? and if we do use it how can we persist it? am I thinking in relational way here instead of OO?

 Thanks for the wonderful Post! I've been really enjoying the design patterns revisited posts.

Mario Schwede replied on Wed, 2008/07/30 - 2:38pm

@Ali You can find the decorator pattern implemented in Java IO. But there it is maybe not the best way. There are two different class hierarchies one for bytes and another for unicode. This is a not a nice thing. Maybe now a day with generics it could be only one interface hierarchie for both.

 The problem with the decorator pattern is that you are free which sequences of decorators you concatenate. There will be constructs which doesnt make sense. But there are no possibilities to prevent them.

Another problem is, if  an interface has many methods and you only whant to decorate some of them, you have to write a lot of boilerplate code. The next problem is if the interface grows you have to correct every decorator (there will be many of them). But there is a nice workaround from Joshua Bloch in Effective java:


class CarForwarder implements Car  
{
private final Car car

public CarForwarder(Car car)
{
this.car = car;
}
// Forward every car method to car
}

class CarImpl implements Car
{
// Do car things
}

class CrazyCar extends CarForwarder
{
public CrazyCar(Car car)
{
super(car);
}
// Override as you like to make some crazy things.
}

public class TestCrazyCar
{
public static main(String... args)
{
new CrazyCar(new CarImpl);
}
}

 

 

Murat Yener replied on Wed, 2008/07/30 - 6:26pm in response to: Ali Anwar

Yes you can do that but et me tell you why it would be more painful. First you need a new object class like "Extras" and this one will challenge other features and needs of the software. First you need to add all this extras class crud functions (however in decorator you dont need to since everything implements same).  Second all the objects are seriliazed and transfered from Java server to .net handhelds, which means instead of using decorator's automatic price calculation you need to code the price calculator. Third since you have a new object type you need to add special handlers for seriliaze and deserilizers on both sides.

Your approach was quite ok with the problem on your mind (actually the problem i described) but the problems and other needs may crash with your design. Thats what design patterns for, even if sometimes they dont look like the perfect solution they are the most compatible ones with current and future requests and functionality. But of course this shouldn't lead you to use extensive and overuse of design patterns.

Thanks for evaluating patterns with other approaches.  No answer is guaranteed to be the best :) i appreaciate your approach to find a simpler solution.

Romen Law replied on Wed, 2008/07/30 - 7:06pm

I still wonder how you implement this in the restaurant example practically. I mean, in real life, won't you store the product catalog (menu) in some form of database (xml, rdbms...), or at least use meta-data so that your product catalog can be changed by the user? Writing each ingredient as an interface or class will be hardcoding the whole product catalog, right?

cheers

romen

Edmund Fong replied on Thu, 2008/07/31 - 12:06am

After reading design patterns website/book and before designing my own system, I have downloaded jHotdraw, http://www.randelshofer.ch/oop/jhotdraw/index.html,to identify what design patterns they use and how to use in real world。

Murat Yener replied on Thu, 2008/07/31 - 12:51am in response to: Romen Law

Sure we did not code every product or ingredient..

We had a product class which includes product id, name, and other details which belongs to an order object. The problem was our product's detail fiend was string base so only text base details can be added and those can not change the price field of the product. However with the decorator we can build a class named productDetails so it can decorate product instances and since they are sharing the same interface they can all be added to order object which keeps products as list.

In this example decorating also very practical because even after the code implemented lacking detail object, it is very easy to modify without changing other parts. When we add the decorator we dont change neither the product  nor the order objects since the decorator is in the same interface with product andcan wrap otherdetails or products.

 I hope I am clear enough this time..

 Ps. the software can run on both mySQL and postgre without any change, and all items including product, restaurant schema, stocks... etc can be added, deleted or modified through admin part with in the software

Maciej Klepaczewski replied on Thu, 2008/07/31 - 1:21am

You're sooo wrong with using decorator pattern to solve this kind of problems. Note, that You have to pre-create class for each product. What if one of Your customers would like to add new ingredient after deployment of the application? They would have to get a new class for this ingredient, which would mean that application would have to be recompiled and deployed again. Also, what if some of Your customers would be using this software for pizza restaurants, some for sushi bar and some for coffee shop? Would You create hundreds or thousands of decorators to represent each available extra?

It's nice to see that people are aware of design patterns. It's bad when they use it wrong way.

Murat Yener replied on Thu, 2008/07/31 - 1:43am in response to: Maciej Klepaczewski

I suggest you to re-read the post and my previous answer lucek. There is no new class for any product or ingredient. There is only one product class and with the decorator again only one detail class (which you call ingredient which i dont know why).

Different instances of product, detail, order, account (whatever you can imagine) are stored in the database. Someone who designs or thinks the opposite like declaring concrete products must be mad.

 Incase I am not clear let me give you an example;

lets say our main object is Product (which means you dont create classes like chicken, hamburger and meatball they are instances not classes you store at db) and there is the decorator class Detail (like sauce, double size, with fries but again all using the same class Detail and stored in the DB again not classes).

 That software may not be the most complete one but runs over a dozen of restaurant including some real big and complicated ones. you can create unlimited product (or any other instances of objects) with the admin console and as soon as they are saved they can be used by client terminals. Such a solution You mentioned will result in building a new binary with new set of classes for each restaurant which is totaly useless. When you build software you need to make reusable so with few modifications you can deploy it to several customers. Can you imagineMicrosoft building a totaly new windows to every customer lucek?

I hope I am clear enough this time.. and i suggest you to re-read the post.

Ali Anwar replied on Thu, 2008/07/31 - 3:19am

@yenerm Thanks a lot for your explanation, actually I do see now how it can fit certain situations and scenarios to use the pattern. In more controlled environment it would make total sense, sometime you really have to enforce it, also, if I can't make changes to the original class (incase of commercial or for the sake of not breaking the code). OK, I still prefer my solution, specially if I'm using something like DB4O where I don't have to do any CRUD. Many Thanks, and please refresh our knowledge with patterns again with excellent post.

@All I just want to indicate that I'm so thankful that someone put sometime and shared a his thought and experience with us, there is after all no wrong or right way of solving a problem, there is only one fact the client appreciate, which is "Problem Solved" even if I use BASIC to do it :)

Ilgar Mashayev replied on Thu, 2008/10/09 - 11:59pm

In my opinion example with pizza is incorrect, this is misuse of the pattern, because pattern's purpose is to bring additional functionality. Your case could be easily done using some list of options inside of main object, as Ali Anwar said in his first comment. 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.