Decorator

      Composite Computer Science Design Patterns
      Decorator
      Facade

      Various examples of the decorator pattern.

      Implementation in C#

      This example illustrates a simple extension method for a bool type.

      using System;
       
      static class BooleanExtensionMethodSample
      {
          public static void Main()
          {
              bool yes = true;
              bool no = false;
              // Toggle the booleans! yes should return false and no should return true.
              Console.WriteLine(yes.Toggle());
              Console.WriteLine(no.Toggle());
          }
          // The extension method that adds Toggle to bool.
          public static bool Toggle(this bool target)
          {
              // Evaluate the input and then return the opposite value.
              if (target)
                  return false;
              else
                  return true; // Satisfy the compiler in case of a null value.
          }
      }
      
      Implementation in Java

      First Example (window/scrolling scenario)

      The following Java example illustrates the use of decorators using the window/scrolling scenario.

      // the Window abstract class
      public abstract class Window {
          public abstract void draw(); // draws the Window
          public abstract String getDescription(); // returns a description of the Window
      }
       
      // extension of a simple Window without any scrollbars
      class SimpleWindow extends Window {
          public void draw() {
              // draw window
          }
       
          public String getDescription() {
              return "simple window";
          }
      }
      

      The following classes contain the decorators for all Window classes, including the decorator classes themselves.

      // abstract decorator class - note that it extends Window
      abstract class WindowDecorator extends Window {
          protected Window decoratedWindow; // the Window being decorated
       
          public WindowDecorator (Window decoratedWindow) {
              this.decoratedWindow = decoratedWindow;
          }
          public void draw() {
              decoratedWindow.draw(); //delegation
          }
          public String getDescription() {
              return decoratedWindow.getDescription(); //delegation
          }
      }
       
      // the first concrete decorator which adds vertical scrollbar functionality
      class VerticalScrollBarDecorator extends WindowDecorator {
          public VerticalScrollBarDecorator (Window decoratedWindow) {
              super(decoratedWindow);
          }
       
          @Override
          public void draw() {
              super.draw();
              drawVerticalScrollBar();
          }
       
          private void drawVerticalScrollBar() {
              // draw the vertical scrollbar
          }
       
          @Override
          public String getDescription() {
              return super.getDescription() + ", including vertical scrollbars";
          }
      }
       
      // the second concrete decorator which adds horizontal scrollbar functionality
      class HorizontalScrollBarDecorator extends WindowDecorator {
          public HorizontalScrollBarDecorator (Window decoratedWindow) {
              super(decoratedWindow);
          }
       
          @Override
          public void draw() {
              super.draw();
              drawHorizontalScrollBar();
          }
       
          private void drawHorizontalScrollBar() {
              // draw the horizontal scrollbar
          }
       
          @Override
          public String getDescription() {
              return super.getDescription() + ", including horizontal scrollbars";
          }
      }
      

      Here's a test program that creates a Window instance which is fully decorated (i.e., with vertical and horizontal scrollbars), and prints its description:

      public class DecoratedWindowTest {
          public static void main(String[] args) {
              // create a decorated Window with horizontal and vertical scrollbars
              Window decoratedWindow = new HorizontalScrollBarDecorator (
                      new VerticalScrollBarDecorator(new SimpleWindow()));
       
              // print the Window's description
              System.out.println(decoratedWindow.getDescription());
          }
      }
      

      The output of this program is "simple window, including vertical scrollbars, including horizontal scrollbars". Notice how the getDescription method of the two decorators first retrieve the decorated Window's description and decorates it with a suffix.

      ↑Jump back a section

      Second Example (coffee making scenario)

      The next Java example illustrates the use of decorators using coffee making scenario. In this example, the scenario only includes cost and ingredients.

      // The abstract Coffee class defines the functionality of Coffee implemented by decorator
      public abstract class Coffee {
          public abstract double getCost(); // returns the cost of the coffee
          public abstract String getIngredients(); // returns the ingredients of the coffee
      }
       
      // extension of a simple coffee without any extra ingredients
      public class SimpleCoffee extends Coffee {
          public double getCost() {
              return 1;
          }
       
          public String getIngredients() {
              return "Coffee";
          }
      }
      

      The following classes contain the decorators for all Coffee classes, including the decorator classes themselves..

      // abstract decorator class - note that it extends Coffee abstract class
      public abstract class CoffeeDecorator extends Coffee {
          protected final Coffee decoratedCoffee;
          protected String ingredientSeparator = ", ";
       
          public CoffeeDecorator(Coffee decoratedCoffee) {
              this.decoratedCoffee = decoratedCoffee;
          }
       
          public double getCost() { // implementing methods of the abstract class
              return decoratedCoffee.getCost();
          }
       
          public String getIngredients() {
              return decoratedCoffee.getIngredients();
          }
      }
       
      // Decorator Milk that mixes milk with coffee
      // note it extends CoffeeDecorator
      class Milk extends CoffeeDecorator {
          public Milk(Coffee decoratedCoffee) {
              super(decoratedCoffee);
          }
       
          public double getCost() { // overriding methods defined in the abstract superclass
              return super.getCost() + 0.5;
          }
       
          public String getIngredients() {
              return super.getIngredients() + ingredientSeparator + "Milk";
          }
      }
       
      // Decorator Whip that mixes whip with coffee
      // note it extends CoffeeDecorator
      class Whip extends CoffeeDecorator {
          public Whip(Coffee decoratedCoffee) {
              super(decoratedCoffee);
          }
       
          public double getCost() {
              return super.getCost() + 0.7;
          }
       
          public String getIngredients() {
              return super.getIngredients() + ingredientSeparator + "Whip";
          }
      }
       
      // Decorator Sprinkles that mixes sprinkles with coffee
      // note it extends CoffeeDecorator
      class Sprinkles extends CoffeeDecorator {
          public Sprinkles(Coffee decoratedCoffee) {
              super(decoratedCoffee);
          }
       
          public double getCost() {
              return super.getCost() + 0.2;
          }
       
          public String getIngredients() {
              return super.getIngredients() + ingredientSeparator + "Sprinkles";
          }
      }
      

      Here's a test program that creates a Coffee instance which is fully decorated (i.e., with milk, whip, sprinkles), and calculate cost of coffee and prints its ingredients:

      public class Main {
       
          public static final void main(String[] args) {
      Coffee c = new SimpleCoffee();
      System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
       
      c = new Milk(c);
      System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
       
      c = new Sprinkles(c);
      System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
       
      c = new Whip(c);
      System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
       
      // Note that you can also stack more than one decorator of the same type
      c = new Sprinkles(c);
      System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
          }
       
      }
      

      The output of this program is given below:

      Cost: 1.0 Ingredient: Coffee
      Cost: 1.5 Ingredient: Coffee, Milk
      Cost: 1.7 Ingredient: Coffee, Milk, Sprinkles
      Cost: 2.4 Ingredient: Coffee, Milk, Sprinkles, Whip

      Implementation in C++
      ↑Jump back a section

      Coffee making scenario

      # include <iostream>
      # include <string>
       
      // The abstract coffee class
      class Coffee
      {
      public:
          virtual double getCost() = 0;
          virtual std::string getIngredient() = 0;
      };
       
      // Plain coffee without ingredient
      class SimpleCoffee:public Coffee
      {
      private:
          double cost;
          std::string ingredient;
       
      public:
          SimpleCoffee()
          {
              cost = 1;
              ingredient = std::string("Coffee");
          }
          double getCost()
          {
              return cost;
          }
          std::string getIngredient()
          {
              return ingredient;
          }
      };
       
      // Abstract decorator class
      class CoffeeDecorator:public Coffee
      {
      protected:
          Coffee & decoratedCoffee;
      public:
          CoffeeDecorator(Coffee & decoratedCoffee):decoratedCoffee(decoratedCoffee){}
      };
       
      // Milk Decorator
      class Milk:public CoffeeDecorator
      {
      private:
          double cost;
       
      public:
          Milk(Coffee & decoratedCoffee):CoffeeDecorator(decoratedCoffee)
          {
              cost = 0.5;
          }
          double getCost()
          {
              return cost + decoratedCoffee.getCost();
          }
          std::string getIngredient()
          {
              return "Milk "+decoratedCoffee.getIngredient();
          }
      };
       
      // Whip decorator
      class Whip:public CoffeeDecorator
      {
      private:
          double cost;
       
      public:
          Whip(Coffee & decoratedCoffee):CoffeeDecorator(decoratedCoffee)
          {
              cost = 0.7;
          }
          double getCost()
          {
              return cost + decoratedCoffee.getCost();
          }
          std::string getIngredient()
          {
              return "Whip "+decoratedCoffee.getIngredient();
          }
      };
       
      // Sprinkles decorator
      class Sprinkles:public CoffeeDecorator
      {
      private:
          double cost;
       
      public:
          Sprinkles(Coffee & decoratedCoffee):CoffeeDecorator(decoratedCoffee)
          {
              cost = 0.6;
          }
          double getCost()
          {
              return cost + decoratedCoffee.getCost();
          }
          std::string getIngredient()
          {
              return "Sprinkles "+decoratedCoffee.getIngredient();
          }
      };
       
      // Here's a test
      int main()
      {
          Coffee* sample;
          sample = new SimpleCoffee();
          sample = new Milk(*sample);
          sample = new Whip(*sample);
          std::cout << sample->getIngredient() << std::endl;
          std::cout << "Cost: " << sample->getCost() << std::endl;
      }
      

      The output of this program is given below:

      Whip Milk Coffee
      Cost: 2.2

      Implementation in JavaScript
      // Class to be decorated
      function Coffee() {
          this.cost = function() {
      return 1;
          };
      }
       
      // Decorator A
      function Milk(coffee) {
          this.cost = function() {
      return coffee.cost() + 0.5;
          };
      }
       
      // Decorator B
      function Whip(coffee) {
          this.cost = function() {
      return coffee.cost() + 0.7;
          };
      }
       
      // Decorator C
      function Sprinkles(coffee) {
          this.cost = function() {
      return coffee.cost() + 0.2;
          };
      }
       
      // Here's one way of using it
      var coffee = new Milk(new Whip(new Sprinkles(new Coffee())));
      alert( coffee.cost() );
       
      // Here's another
      var coffee = new Coffee();
      coffee = new Sprinkles(coffee);
      coffee = new Whip(coffee);
      coffee = new Milk(coffee);
      alert(coffee.cost());
      
      Implementation in Python
      ↑Jump back a section

      Window System

      # the Window base class
      class Window(object):
          def draw(self, device):
              device.append('flat window')
          def info(self):
              pass
      # The decorator pattern approch
      class WindowDecorator:
          def __init__(self, w):
              self.window = w
          def draw(self, device):
              self.window.draw(device)
          def info(self):
              self.window.info()
       
      class BorderDecorator(WindowDecorator):
          def draw(self, device):
              self.window.draw(device)
              device.append('borders')
       
      class ScrollDecorator(WindowDecorator):
          def draw(self, device):
              self.window.draw(device)
              device.append('scroll bars')
       
      def test_deco():
          # The way of using the decorator classes
          w = ScrollDecorator(BorderDecorator(Window()))
          dev = []
          w.draw(dev)
          print dev
      test_deco()
      

      Difference between subclass method and decorator pattern

      # The subclass approch
      class BorderedWindow(Window):
          def draw(self, device):
              super(BorderedWindow, self).draw(device)
              device.append('borders')
       
      class ScrolledWindow(Window):
          def draw(self, device):
              super(ScrolledWindow, self).draw(device)
              device.append('scroll bars')
       
      # combine the functionalities using multiple inheritance.
      class MyWindow(ScrolledWindow, BorderedWindow, Window):
          pass
       
      def test_muli():
          w = MyWindow()
          dev = []
          w.draw(dev)
          print dev
       
      def test_muli2():
          # note that python can create a class on the fly.
          MyWindow = type('MyWindow', (ScrolledWindow, BorderedWindow, Window), {})
          w = MyWindow()
          dev = []
          w.draw(dev)
          print dev
       
      test_muli()
      test_muli2()
      
      ↑Jump back a section

      Dynamic languages

      The decorator pattern can also be implemented in dynamic languages either with interfaces or with traditional OOP inheritance.


      Clipboard

      To do:
      Add more illustrations.


      Composite Computer Science Design Patterns
      Decorator
      Facade


      You have questions about this page?
      Ask it here:


      Create a new page on this book:

      ↑Jump back a section
      Last modified on 21 May 2013, at 20:11