I’ve been inthe dark as far as the Decorator pattern is concerned. I knew, inprinciple, how it works, but I can see that my understanding was veryincomplete. Plus, I never had a chance to useit. While reading the Head First Design Patternsbook, Idiscovered something basic that: when you wrap an object several timesand then call a method on it, it will be called as many times as it waswrapped. The trick? Keepa reference to the object — you’re creating a chain.
<font
Let me gothrough this step by step. By example. This is thebook’s example, the Starbuzz Coffee decorator.
<font
A simpleinterface.
<fontpublic interfaceBeverage {
<fontpublic String getDescription();
<fontpublic BigDecimal getCost();
<font}
We have severalcoffee types, Dark Roast being one of them.
<fontpublic classDarkRoast implementsBeverage {
<font public BigDecimal getCost() {
<font return newBigDecimal(“1.55″);
<font }
<font public String getDescription() {
<font return“Dark Roast”;
<font }
<font}
When orderingcoffee, you can pick a coffee type (Dark Roast, Latte, etc), and youcan also add on to the coffee. For instance, you can add a whip creamon top, or add a shot of expresso to it. Which, of course, adds to theprice. You could extend Beverage with all of the types, but that’s toomany classes. Here’swhere the decorator pattern comes into play.
Here’sthe solution. You define the AddOnDecorator and extend it with thedifferent add ons.
<font/** It’sjust an empty class */
<fontpublic abstractclassAddOnDecorator implementsBeverage { }
<font
<fontpublic classExpresso extendsAddOnDecorator {
<fontBeveragebeverage;
<fontpublic Expresso(Beverage beverage) {
<font this.beverage =beverage;
<font}
<fontpublic BigDecimal getCost() {
<font return newBigDecimal(“0.25″).add(beverage.getCost());
<font}
<fontpublic String getDescription() {
<font return beverage.getDescription()+ “, with Expresso”;
<font }
}
<font
<fontpublic classWhip extendsAddOnDecorator {
<fontBeveragebeverage;
<fontpublic Whip(Beverage beverage) {
<fontthis.beverage =beverage;
<font }
<fontpublic BigDecimal getCost() {
<fontreturn newBigDecimal(“0.10″).add(beverage.getCost());
<font }
<fontpublic String getDescription() {
<fontreturn beverage.getDescription()+ “, Whipped”;
<font}
<font}
<font
<fontpublic classStarbuzzCoffee {
<fontpublic staticvoidmain(String[] args) {
<fontBeveragedarkRoast = newDarkRoast();
<fontdarkRoast= newExpresso(darkRoast);
<fontdarkRoast= newWhip(darkRoast);
<fontSystem.out.println(darkRoast.getDescription()+ ” costs “
<font+darkRoast.getCost());
<font}
<font}
WhenI first looked at the code, I was confused. I thought that newWhip(…) would just override it,right?
Thisis what gets printed: Dark Roast, with Expresso, Whippedcosts 1.90
You get the beverage you want(DarkRoast), you pass it to the Expresso wrapper, which in turn passesit to the Whip wrapper.
Firstthe Expressowrapper is called, itreceives the dark roast beverage. Then the dark roast is passed againto the Whip wrapper. If you look closely (and this isa little confusing), when an Expresso is instantiated, it receives the beverage andmakes a local copy (so it is never lost). Essentially, a chain is made.When the action on the final object is made, the chain is traversed andthe beverage object is passed around. That’s how this patternworks. (Wow, I learn something (basic) every day. )
The Decoratorpattern is cool. It rocks. It lets you keep adding functionality and still keep the objectscohesive (as you’re not bloating the objects). No coupling as well.Nice.
Reference
Head First Design Patterns, the example above was taken from the book