File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes OO, Patterns, UML and Refactoring and the fly likes HeadFirst Design Patterns - Decorator Chapter Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Engineering » OO, Patterns, UML and Refactoring
Bookmark "HeadFirst Design Patterns - Decorator Chapter" Watch "HeadFirst Design Patterns - Decorator Chapter" New topic
Author

HeadFirst Design Patterns - Decorator Chapter

steve souza
Ranch Hand

Joined: Jun 26, 2002
Posts: 861
I am currently reading HeadFirst Design Patterns, and although their example of the decorator pattern gets the point across from an implementation standpoint, somehow I think their example misses the mark from a modelling standpoint.

In the example they use a Beverage class (i.e. espresso, houseblend,...), and they extend CondimentDecorator (soy, mocha, whip) from Beverage. So both coffee and individual condiments are considered to be a Beverage. So to construct a houseblend coffee, with mocha, whip and soy the do the following.



Although this works from an implemention standpoint I wonder if it is the best use of the decorator pattern.

1) Firstly, by having Condiments extend Beverage you are saying that the Condiment IS-A beverage and I think most would agree a condiment is not a beverage (i.e. The Mocha or Whip condiments are not beverages)

2) The order of the constructor chaing puts the emphasis on the condiments and not the coffee. I prefer the coffee to assume the first position in the decorator chain as it makes it more clear that in the end this beverage is a coffee, but admittedly this may just be personal style. But, i think the following is more clear:



3) From a modeling relationship I think the decorator concept here shoud be aborted in favor of a more explicit API that adds condiments to a beverage. I think this more clearly reflects the relationship of a beverage CONTAINING condiments. i.e. the following:


And once this approach is taken the Decorator pattern is really no longer needed.

I think the Decorator pattern fits well with the Java IO example though as the concept of containership/ownership does not exist between the decorator IO classes. They are just decorating each other.

Thoughts?


http://www.jamonapi.com/ - a fast, free open source performance tuning api.
JavaRanch Performance FAQ
Elisabeth Robson
author
Ranch Hand

Joined: May 14, 2004
Posts: 173
    
    6
Hi Steve,

I'm curious why you say that the Java I/O classes work as Decorators because they are "just decorating each other" when you could apply exactly the same argument as you did to the beverages and condiments.

Look at the diagram for the I/O classes (page 101). A BufferedInputStream is NOT an input stream by itself - it requires a concrete component class to provide that funtionality. All it does is buffer. It provides additional functionality to the component class, but cannot perform the function of the concrete component class on its own. The relationship, just like in the Beverage Condiment relationship in the Coffee example is an IS-A relationship - the BufferedInputStream IS-A InputStream, but it actually isn't. It cannot read from a file, or a string. Therefore, a BufferedInputStream is not technically an inputstream despite the IS-A relationship.

I think you will find this to be true of most, if not all, designs using the Decorator Pattern. The purpose of the pattern is for the decorators to ADD functionality to a component class. The reason they have this IS-A relationship is so that, to the client, they look the same, and the client doesn't have to care about what decorators have been added. This relationship is there, not in the traditional "inheritance" view of IS-A, but rather from the client's perspective of IS-A: for the interface.

Your suggestion for a solution for the coffee example - to add condiments through a method in Beverage - is certainly a way to do it; however, keep in mind that by doing it that way, there must be functionality within the Beverage class to 1) store the additional condiments and 2) keep track of them in such a way that behavior can be added and in the correct order. This adds complexity to the Beverage class, and, depending on how it's coded, may require that you CHANGE the Beverage class if/when you add a new kind of condiment. The whole point of the Decorator class is that you can continue to add new types of Decorators without ever having to change the component base class. Not to say your alternative wouldn't work - it would - it's just a different way of doing it, and as always, one needs to keep in mind the intended use and expected path of change down the road.

Elisabeth


Co-Author of Head First JavaScript Programming
steve souza
Ranch Hand

Joined: Jun 26, 2002
Posts: 861
Thanks for the response Elisabeth.

Let's not address the java I/O example as truthfully I didn't study that one very much. Still I think my points about the Beverage/Condiments example stands

1) A condiment is not a beverage and to model it that way should be avoided if possible. In this case I think the method I mentioned does provides a simple implementation and is more true to the relationship of beverages and condiments.



keep in mind that by doing it that way, there must be functionality within the Beverage class to 1) store the additional condiments and 2) keep track of them in such a way that behavior can be added and in the correct order. This adds complexity to the Beverage class, and, depending on how it's coded, may require that you CHANGE the Beverage class if/when you add a new kind of condiment.


2) Yes you would have to store Condiments in my approach. This however is quite simple. Probably as easy as setting up the decorator chain. I would suggest an ArrayList which will also retain the order they were put in. This logic is trivial.

Assuming you don't change the condiment interface I wouldn't think changes would be needed in the Beverage class if you added new condiment types.

Also, I should add I am a fan of the decorator pattern and have used it in my open source projects.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by steve souza:
1) Firstly, by having Condiments extend Beverage you are saying that the Condiment IS-A beverage and I think most would agree a condiment is not a beverage (i.e. The Mocha or Whip condiments are not beverages)


IS-A is just a *heuristic* for inheritance relationships in code. And not a very good one...

A better one is the Liskov Substitution Principles, which says that the Condiment instance should be able to be used anywhere a beverage can be used, without the clients even knowing. That's certainly true, isn't it.

It was an early marketing gag to say that OO somehow was meant to model the real world. The true power of OO is as a tool to manage dependencies. In this case, you can add Condiments to a beverage without touching neither the Beverage class, nor its clients. That is a very powerfull way to conform to the Open Closed Principle, another very important principle to make code more maintainable and extensible.


2) The order of the constructor chaing puts the emphasis on the condiments and not the coffee.


Not if you are used to the Decorator pattern, I'd say. Then it's quite clear that the innermost instance is the most important one.

3) From a modeling relationship I think the decorator concept here shoud be aborted in favor of a more explicit API that adds condiments to a beverage. I think this more clearly reflects the relationship of a beverage CONTAINING condiments.


But why is it important to you to reflect that relationship inside your code - so important that you would rather have the code more complex and less flexible to do that?

By the way, if that were that important to me, I'd probably implement a Builder for that and still use the Decorator internally, so that I can get the best of both worlds.


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
steve souza
Ranch Hand

Joined: Jun 26, 2002
Posts: 861

But why is it important to you to reflect that relationship inside your code - so important that you would rather have the code more complex and less flexible to do that?


I don't see how the code for my solution is any more complex, and the clarity of the relationships is better. I think I've clearly stated my points, and I stand by them. We may have to agree to disagree

I think you are more free with your meaning of IS-A than I am. I think anything that implements Beverage should be a beverage. It aids any maintenance developers ability to understand code if we leverage their everyday understanding of what a beverage and condiment are. Most people don't think of condiments as being beverages. I don't like surprises in code.

If you start to add methods to a beverage such as drink() and you have a condiment such as Sugar it seems to stretch the Condiment model a bit to think drink() makes much sense for sugar. But due to the tight coupling you would have to implement this drink() method for all Condiments.

I guess I'll flip the argument. What in this case is the decorator giving you that my solution is not? Plus someone doesn't have to understand the Decorator pattern to understand the code.



Not if you are used to the Decorator pattern, I'd say. Then it's quite clear that the innermost instance is the most important one.

I don't think the order that you choose in the decorator chain matters, and the pattern could be implemented either way.
[ January 05, 2005: Message edited by: steve souza ]
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by steve souza:
I don't see how the code for my solution is any more complex


Well, it requires Beverage to be coupled to the Condiments, and to contain special code to handle them. That certainly makes Beverage more complex. I typically prefer many small, simple classes over less, more complex classes.

I think you are more free with your meaning of IS-A than I am.


Actually I don't use IS-A as a rule for inheritance in code at all, as I tried to explain. So I'm quite agnostic to the meaning of it...

I think anything that implements Beverage should be a beverage. It aids any maintenance developers ability to understand code if we leverage their everyday understanding of what a beverage and condiment are. Most people don't think of condiments as being beverages. I don't like surprises in code.

If you start to add methods to a beverage such as drink() and you have a condiment such as Sugar it seems to stretch the Condiment model a bit to think drink() makes much sense for sugar. But due to the tight coupling you would have to implement this drink() method for all Condiments.


Well, I can actually resonate with that feeling. I wouldn't drop the Decorator pattern because of that, though, but rather think about better names for the Decorators. What, for example, about SugaredBeverage?

Beverage beverage = new SugaredBeverage(new Coffee());

Looks better to me. (It's also more similar to the naming of the java.io classes, by the way.)


I guess I'll flip the argument. What in this case is the decorator giving you that my solution is not?


SugaredBeverage can be applied to any Beverage implementation - without the developer of a Beverage implementation having to worry about it at all. That's quite a big advantage, in my opinion.

Plus someone doesn't have to understand the Decorator pattern to understand the code.


Well, one does have to understand other code instead. And actually I think a developer who doesn't know the Decorator pattern would do well to learn it...

I don't think the order that you choose in the decorator chain matters, and the pattern could be implemented either way.


I don't think so. The innermost instance needs to be the instance with the main responsibility, wrapped by the Decorators adding functionality. I don't see how it could work the other way around.
steve souza
Ranch Hand

Joined: Jun 26, 2002
Posts: 861

I wouldn't drop the Decorator pattern because of that, though, but rather think about better names for the Decorators. What, for example, about SugaredBeverage?

Beverage beverage = new SugaredBeverage(new Coffee());

Looks better to me. (It's also more similar to the naming of the java.io classes, by the way.)


Ok, I can live with this! Unlike Sugar, it is easy to see that SugaredBeverage is a beverage.

I think the traditional use of chaining the decorator constructors isn't very useful in this case. Any realistic modeling of this process would be so dynamic (i.e. double whip, mocha, with soy and and extra espresso shot) a developer couldn't code the decorator chain and so you might as well have some form of addCondiment() method. This approach is clearer.
Jeroen Wenting
Ranch Hand

Joined: Oct 12, 2000
Posts: 5093
A better design (from a pure OO perspective) might have been to define a common baseclass for both condiments and beverages.
Say have an abstract base Ingredient from which you get abstract classes Condiment and Beverage.
Have one class Product which wraps an ingredient (which wraps other ingredients) and provide interfaces to act on it.
Change the example to decorate Ingredients with each other and package the final collection in a Product which is prepared, then served.

This would of course make the example a lot more complex, taking away from the description of the pattern for reasons of politically correct OO.


42
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jeroen Wenting:
A better design (from a pure OO perspective) might have been to define a common baseclass for both condiments and beverages.


What would you gain by doing so?
steve souza
Ranch Hand

Joined: Jun 26, 2002
Posts: 861
Like I said, I can live with Ilja's solution still I'm not totally convinced. His solution was:

Beverage beverage=new SugaredBeverage(new Coffeee());

Do you guys think the best solution to implement a person would be something like the following:

Person me=new Eyes(new Arms(new Hands(new Legs(new Feet(new Nose(new Person()))))));

Say Person had various methods like walk(), talk(), stand(), think() etc. Then all of the constiuent body parts would have to implement these methods. Even if you change the names of the body parts to something like ArmsPerson, or even ArmsDecorator it doesn't feel like a good solution to me (I wouldn't want to name my classes something like ArmsDecorator anyway as it reveals too much about the implementation). I view the beverage solution in a similar way.
[ January 06, 2005: Message edited by: steve souza ]
Jeroen Wenting
Ranch Hand

Joined: Oct 12, 2000
Posts: 5093
Originally posted by Ilja Preuss:


What would you gain by doing so?


it would take away the argument that a condiment isn't a beverage... I admit it's a bit contrived
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
No, in your example it probably doesn't make sense, because a Person without Legs cannot walk.

The Decorator pattern is a good choice when a decorator doesn't change *what* can be done with an object, but only *adds* to already existing behaviour.
Jeroen Wenting
Ranch Hand

Joined: Oct 12, 2000
Posts: 5093
That's why I proposed wrapping the entire construct in a single Product class which would contain the actual code to create the product.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jeroen Wenting:
That's why I proposed wrapping the entire construct in a single Product class which would contain the actual code to create the product.


But, in contrast to the Person example, a Beverage without any Condiment already is fully functional, the way I understand it. That's an important difference.
Lance Harper
Greenhorn

Joined: Jan 10, 2005
Posts: 1
Originally posted by steve souza:


Do you guys think the best solution to implement a person would be something like the following:

Person me=new Eyes(new Arms(new Hands(new Legs(new Feet(new Nose(new Person()))))));

Say Person had various methods like walk(), talk(), stand(), think() etc. Then all of the constiuent body parts would have to implement these methods. Even if you change the names of the body parts to something like ArmsPerson, or even ArmsDecorator it doesn't feel like a good solution to me (I wouldn't want to name my classes something like ArmsDecorator anyway as it reveals too much about the implementation). I view the beverage solution in a similar way.


I think you are comparing apples and oranges. A person is assumed to already have hands, arms, legs, etc. It would be built into the Person class. A Beverage by default would not have any condiments and decorating would extend functionality, not specify what should have been implemented initially.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: HeadFirst Design Patterns - Decorator Chapter