{"id":205,"date":"2006-09-14T11:20:23","date_gmt":"2006-09-14T11:20:23","guid":{"rendered":"http:\/\/kubasek.com\/blog\/pragmatic_craftsman\/?p=205"},"modified":"2006-09-14T11:20:23","modified_gmt":"2006-09-14T11:20:23","slug":"the-decorator-pattern","status":"publish","type":"post","link":"https:\/\/pragmaticcraftsman.kubasek.com\/2006\/09\/14\/the-decorator-pattern\/","title":{"rendered":"The Decorator Pattern"},"content":{"rendered":"<p>I&#8217;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&nbsp;never had a chance to useit.&nbsp;While reading the <em>Head First Design Patterns<\/em>book<span>,<\/span> 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.<span> The trick? Keepa reference to the object &#8212; you&#8217;re creating a chain. <\/span><\/p>\n<p>&lt;font &nbsp;<\/font><\/font><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt\">Let me gothrough this step by step. By example.&nbsp;<span>This is&nbsp;<\/span>thebook&#8217;s example, the Starbuzz Coffee decorator.<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt\">&lt;font &nbsp;<\/font><\/font><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt\">A simpleinterface.<\/span><\/p>\n<p class=\"MsoNormal\" style=\"margin: 0in 0in 0pt\">&nbsp;<\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<b>public<\/span><\/b> <b>interface<\/span><\/b>Beverage {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt;text-indent: 0.2in\">&lt;font<b>public<\/span><\/b> String getDescription();<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt;text-indent: 0.2in\">&lt;font<b>public<\/span><\/b> BigDecimal getCost();<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p><span style=\"font-size: 10pt\">We have severalcoffee types, Dark Roast being one of them.<\/span><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<b>public<\/span><\/b> <b>class<\/span><\/b>DarkRoast <b><span>implements<\/span><\/b>Beverage {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<b>&nbsp; <\/span>public<\/span><\/b> BigDecimal getCost() {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<b>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>return<\/span><\/b> <b>new<\/span><\/b>BigDecimal(<span>&#8220;1.55&#8221;<\/span>);<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font &nbsp;&nbsp;&nbsp;}<\/font><\/span><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<span>&nbsp; <\/font><\/span><b>public<\/span><\/b> String getDescription() {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<span style=\"font-size: 10pt\">&nbsp;&nbsp;&nbsp; <\/span><b>return<\/span><\/b><span>&#8220;Dark Roast&#8221;<\/span>;<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<span style=\"font-size: 10pt\">&nbsp; <\/span>}<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p><span style=\"font-size: 10pt\">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&#8217;s toomany classes.<span> <\/span>Here&#8217;swhere the decorator pattern comes into play. <\/span><\/p>\n<p><span style=\"font-size: 10pt;font-family: Arial\">Here&#8217;sthe solution. You define the AddOnDecorator and extend it with thedifferent add ons.<\/span><\/p>\n<p style=\"margin: 0in 0in 0pt\"><b>&lt;font\/** It&#8217;sjust an empty class *\/<\/span><\/font><\/b><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<b>public<\/span><\/b> <b>abstract<\/span><\/b><b><span>class<\/span><\/b>AddOnDecorator <b><span>implements<\/span><\/b>Beverage { }<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\"><font size=\"3\">&lt;font&nbsp;<\/font><\/font><\/span><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<strong>public<\/span><\/strong> <b>class<\/span><\/b>Expresso <b><span>extends<\/span><\/b>AddOnDecorator {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<span style=\"font-size: 10pt\">Beverage<span>beverage<\/span>;<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>public<\/span><\/b> Expresso(Beverage beverage) {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>&nbsp; <\/span>this<\/span><\/b>.beverage<\/span> =beverage;<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>public<\/span><\/b> BigDecimal getCost() {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>&nbsp; <\/span>return<\/span><\/b> <b>new<\/span><\/b>BigDecimal(<span>&#8220;0.25&#8221;<\/span>).add(beverage<\/span>.getCost());<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>public<\/span><\/b> String getDescription() {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>&nbsp; <\/span>return<\/span><\/b> beverage<\/span>.getDescription()+ <span>&#8220;, with Expresso&#8221;<\/span>;<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font }<\/font><\/span><\/p>\n<p style=\"margin: 0in 0in 0pt\"><span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\"><font size=\"3\">&lt;font&nbsp;<\/font><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<b>public<\/span><\/b> <b>class<\/span><\/b>Whip <b><span>extends<\/span><\/b>AddOnDecorator {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<span style=\"font-size: 10pt\">Beverage<span>beverage<\/span>;<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>public<\/span><\/b> Whip(Beverage beverage) {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in;text-indent: 0.2in\">&lt;font<b>this<\/span><\/b>.beverage<\/span> =beverage;<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font }<\/font><\/span><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&nbsp;<\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>public<\/span><\/b> BigDecimal getCost() {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in;text-indent: 0.2in\">&lt;font<b>return<\/span><\/b> <b>new<\/span><\/b>BigDecimal(<span>&#8220;0.10&#8221;<\/span>).add(beverage<\/span>.getCost());<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font }<\/font><\/span><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&nbsp;<\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>public<\/span><\/b> String getDescription() {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in;text-indent: 0.2in\">&lt;font<b>return<\/span><\/b> beverage<\/span>.getDescription()+ <span>&#8220;, Whipped&#8221;<\/span>;<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\"><font size=\"3\">&lt;font&nbsp;<\/font><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<b>public<\/span><\/b> <b>class<\/span><\/b>StarbuzzCoffee {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<b>public<\/span><\/b> <b>static<\/span><\/b><b><span>void<\/span><\/b>main(String[] args) {<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.4in\">&lt;font<span style=\"font-size: 10pt\">BeveragedarkRoast = <b><span>new<\/span><\/b>DarkRoast();<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.4in\">&lt;font<span style=\"font-size: 10pt\">darkRoast= <b><span>new<\/span><\/b>Expresso(darkRoast);<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.4in\">&lt;font<span style=\"font-size: 10pt\">darkRoast= <b><span>new<\/span><\/b>Whip(darkRoast);<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.4in\">&lt;font<span style=\"font-size: 10pt\">System.<i>out<\/span><\/i>.println(darkRoast.getDescription()+ <span>&#8221; costs &#8220;<\/span><\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.6in;text-indent: 0.2in\">&lt;font<span style=\"font-size: 10pt\">+darkRoast.getCost());<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt 0.2in\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p style=\"margin: 0in 0in 0pt\">&lt;font<span style=\"font-size: 10pt\">}<\/span><\/font><\/p>\n<p><span style=\"font-size: 10pt;font-family: Arial\">WhenI first looked at the code, I was confused. I thought that newWhip(&#8230;) would just override it<span>,right?<\/span> <\/span><\/p>\n<p><span style=\"font-size: 10pt;font-family: Arial\">Thisis what gets printed: <em>Dark Roast, with Expresso, Whippedcosts 1.90<\/em><\/span><\/p>\n<p><span style=\"font-size: 10pt;font-family: Arial\"><span>You get the beverage you want(DarkRoast), you pass it to the Expresso wrapper, which in turn passesit to the Whip wrapper. <\/span><\/span><\/p>\n<p><span style=\"font-size: 10pt;font-family: Arial\">Firstthe&nbsp;<span>E<\/span>xpressowrapper is called,&nbsp;<span>itreceives the dark roast beverage. Then the dark roast is passed againto the Whip wrapper.&nbsp;<\/span><span>If you look closely (and this isa little confusing),&nbsp;<\/span>when a<span>n Expresso is&nbsp;<\/span>instantiated<span>,<\/span><span> it receives the beverage andmakes a local copy (so it is never lost). <\/span><span>Essentially, a chain is made.When the action on the final object is made, the chain is traversed andthe beverage object is passed around. <\/span>That&#8217;s&nbsp;<span>how<\/span> this patternworks. (Wow, I learn something (basic) every day. :-))<\/span><\/p>\n<p><span style=\"font-size: 10pt;font-family: Arial\">The Decoratorpattern is cool. It rocks. \ud83d\ude42<span>It lets you keep adding functionality and still keep the objectscohesive (as you&#8217;re not bloating the objects). No coupling as well.Nice.<\/span><\/span><\/p>\n<p><\/font><\/p>\n<p><p><strong>Reference<\/strong><br \/><a href=\"http:\/\/www.amazon.com\/gp\/product\/0596007124\/ref=reg_hu-wl_mrai-recs\/103-5110028-0765410?ie=UTF8\">Head First Design Patterns<\/a>, the example above was taken from the book<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;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&nbsp;never had [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[2],"tags":[],"class_list":["post-205","post","type-post","status-publish","format-standard","hentry","category-architecture-design"],"_links":{"self":[{"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/posts\/205","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/comments?post=205"}],"version-history":[{"count":0,"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/posts\/205\/revisions"}],"wp:attachment":[{"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/media?parent=205"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/categories?post=205"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pragmaticcraftsman.kubasek.com\/wp-json\/wp\/v2\/tags?post=205"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}