In the Head First Design Patterns book, there is a chapter on Decorator pattern. The coffee company currently has a Beverage abstract class which is extended by DarkRoast, Espresso, Decaf etc. Now they start selling condiments which spice up the coffee like whip, mocha etc. To accomodate, the first misguided attempt (that was a nice way to get us started), extends each of the subclasses above to factor in the whip, mocha etc. So we had a DarkRoastWhipMocha, a DarkRoastWhip, a DarkRoastWhipDoubleMocha etc. Then they suggested refactoring this with Decortator pattern. Whip, Mocha become Decorators that implement the same Beverage interface but can wrap concrete beverages like DarkRoast etc and then in the decorated cost() method, first invoke the wrapped (decorated) concrete class's cost() method and then add the cost of the condiment (decorator) before returning the cost.
My question is this... Is this really required? Condiments and coffee types are all products being sold at the outlet. So we just need to have different subtypes for each such condiment and/or product and each has its own cost() method returning its price from a product table for the model which is the unique key differentiating a mocha from a decaf from a whip. Then the Order object simply loops through all the order items which in this case are Beverages, calling each one's cost() method and calculating the sum() as the total of the order. This sounds simpler and cleaner to me. After all each condiment and coffee is a line item in a order slip. Why try to build one object that would try to represent a DarkRoastWhippedDoubleMocha by combining a Mocha decorator with a Whip decorator that wraps a DarkRoast beverage concrete object? Why use Decorator at all? May be iam not good in understanding things, but am i breaking rule here or am i just being stupid? If so how?
Thanks if you read this far... And lots of thanks in advance if you can clarify this to me :-)
Sab<br /> <br />Perfection does not come from belief or faith. Talk does not count for anything. Parrots can do that. Perfection comes through selfless work.<br />Swami Vivekananda
Skimmed the book, but haven't read it - so take this with a grain of salt.
The problem I can see with your approach is that it implies/requires that the Condiments be separately orderable items. IIRC, the company of the book sells only Beverages - it's just branched out into different kinds of Beverages.
If all you actually sell are Beverages, it makes sense to have an Order that is composed of one Beverage per line. Also, with the suggested Decorator pattern, if the customer orders more than one of a given Beverage, computing the cost is more straightforward.
I guess the rule they're implying here is "don't make something a separate object if that's not the way your problem domain actually works." That being said - like everything else in computing, there are a bazillion ways to approach any problem. We can discuss/argue about which is better/best all day, without having to come up with the One True Answer.
Just my tuppence...
In Theory, there is no difference between theory and practice.<br />In Practice, there is no relationship between theory and practice.
Piggy-backing on what Gainey has said, this would also require seperate delivery. Now you are passing an array of items of potentially different types between methods. As opposed to a single beverage item.
Don't try to look at the decorator pattern as the best tool for the job. Try to look at this example use as an illustration of the theory of why one would choose to use the decorator pattern. If you can grasp the theory you have understood the lesson. You may personally choose not to apply it in this case. Such is the way of many examples that try to illustrate a theory without becoming too complicated.
Joined: Aug 29, 2002
Yes i should try to take home the right ideas... Actually, when i posted the topic, my intention was to discuss if this pattern was indeed required to solve this problem. It appears it is not.
Originally posted by Mr. C Lamont Gilbert: Now you are passing an array of items of potentially different types between methods. As opposed to a single beverage item.
Yes thats true. But as long as the different methods and layers program to the Beverage interface, they should be safe i guess.