The Pragmatic Craftsman :: Simplicity from complexity : by Stanley Kubasek ::

The Decorator Pattern

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

Favorite Quote

Topics

Tags

Archive

Currently Reading

Info

© 2001-2024 Stanley Kubasek About me :: Contact me

Me on Twitter

»see more

Recent Entries