Difference between revisions of "Decorator"

From CDOT Wiki
Jump to: navigation, search
m
(Sample Code)
Line 1: Line 1:
[[BTP600]] > [[Decorator]]
+
[[BTP600]] > [[Decorator]]
  
 
Allow new/additional responsibility to be added to an existing object dynamically. Decoratores provide a flexible alternative to subclassing for extending functionality.
 
Allow new/additional responsibility to be added to an existing object dynamically. Decoratores provide a flexible alternative to subclassing for extending functionality.
Line 12: Line 12:
  
 
==Sample Code==
 
==Sample Code==
window/scrolling scenario
+
Beverage is the abstract component class
 
+
  public abstract class Beverage {
// the Window interface
+
     String description = "Unknown Beverage";
  interface Window {
 
     public void draw(); // draws the Window
 
    public String getDescription(); // returns a description of the Window
 
}
 
 
   
 
   
// implementation of a simple Window without any scrollbars
+
     public String getDescription() {
class SimpleWindow implements Window {
+
      return description;
     public void draw() {
 
        // draw window
 
 
     }
 
     }
 
   
 
   
     public String getDescription() {
+
     public abstract double cost(String sz);
        return "simple window";
+
     //static abstract double size();
     }
 
 
  }
 
  }
  
The decorator classes
+
Leaf classes that inherit from Beverage class
 
+
  public class DarkRoast extends Beverage {
// abstract decorator class - note that it implements Window
+
     public DarkRoast() {
  abstract class WindowDecorator implements Window {
+
      description = "Dark Roast Coffee";
     protected Window decoratedWindow; // the Window being decorated
+
    }
 
   
 
   
     public WindowDecorator (Window decoratedWindow) {
+
     public double cost() {
        this.decoratedWindow = decoratedWindow;
+
      return .99;
 
     }
 
     }
 
  }
 
  }
+
 
// the first concrete decorator which adds vertical scrollbar functionality
+
  public class Decaf extends Beverage {
  class VerticalScrollBarDecorator extends WindowDecorator {
+
     public Decaf() {
     public VerticalScrollBarDecorator (Window decoratedWindow) {
+
      description = "Decaf Coffee";
        super(decoratedWindow);
 
 
     }
 
     }
 
   
 
   
     public void draw() {
+
     public double cost() {
        drawVerticalScrollBar();
+
      return 1.05;
        decoratedWindow.draw();
 
 
     }
 
     }
 +
}
 +
 +
Condiment Decorator class
 +
public abstract class CondimentDecorator extends Beverage {
 +
    public abstract String getDescription();
 +
}
 +
 +
Mocha is a concrete decorator class that implements cost() and getDescription()
 +
public class Mocha extends CondimentDecorator {
 +
    Beverage beverage;
 
   
 
   
     private void drawVerticalScrollBar() {
+
     public Mocha(Beverage beverage) {
        // draw the vertical scrollbar
+
      this.beverage = beverage;
 
     }
 
     }
 
   
 
   
 
     public String getDescription() {
 
     public String getDescription() {
        return decoratedWindow.getDescription() + ", including vertical scrollbars";
+
      return beverage.getDescription() + ", Mocha";
    }
 
}
 
 
// the second concrete decorator which adds horizontal scrollbar functionality
 
class HorizontalScrollBarDecorator extends WindowDecorator {
 
    public HorizontalScrollBarDecorator (Window decoratedWindow) {
 
        super(decoratedWindow);
 
 
     }
 
     }
 +
}
 +
 +
Another concrete decorator
 +
public class Vanilla extends CondimentDecorator {
 +
    Beverage beverage;
 
   
 
   
     public void draw() {
+
     public Vanilla(Beverage beverage) {
        drawHorizontalScrollBar();
+
      this.beverage = beverage;
        decoratedWindow.draw();
 
    }
 
 
    private void drawHorizontalScrollBar() {
 
        // draw the horizontal scrollbar
 
 
     }
 
     }
 
   
 
   
 
     public String getDescription() {
 
     public String getDescription() {
        return decoratedWindow.getDescription() + ", including horizontal scrollbars";
+
      return beverage.getDescription() + ", Vanilla";
    }
 
}
 
 
 
main program
 
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());
 
 
     }
 
     }
 
  }
 
  }

Revision as of 13:06, 28 February 2007

BTP600 > Decorator

Allow new/additional responsibility to be added to an existing object dynamically. Decoratores provide a flexible alternative to subclassing for extending functionality.

UML Class diagram of the decorator pattern

Introduction

Decorator, a structual pattern also known as wrapper, adds additional functionality to a class at runtime through composition. Decorators are alternative to subclassing which add behaviour at compile time. By wrapping, it allows us to add things to the component without requiring every subclass to inherit these new qualities. Each decorator class wraps a component, which means the decorator has an instance variable that holds a reference to a component.

Motivation

As an example we can look at graphical user interface toolkits where we want to add responsibility such as scrolling behaviour or border property to individual objects, not to an entire class. By using inheritance to add responsibility to a user interface component is inflexible because it is made statically. A better approach is wrapping the decorator component in another object dynamically.

Sample Code

Beverage is the abstract component class

public abstract class Beverage {
   String description = "Unknown Beverage";

   public String getDescription() {
      return description;
   }

   public abstract double cost(String sz);
   //static abstract double size();
}

Leaf classes that inherit from Beverage class

public class DarkRoast extends Beverage {
   public DarkRoast() {
      description = "Dark Roast Coffee";
   }

   public double cost() {
      return .99;
   }
}
public class Decaf extends Beverage {
   public Decaf() {
      description = "Decaf Coffee";
   }

   public double cost() {
      return 1.05;
   }
}

Condiment Decorator class

public abstract class CondimentDecorator extends Beverage {
   public abstract String getDescription();
}

Mocha is a concrete decorator class that implements cost() and getDescription()

public class Mocha extends CondimentDecorator {
   Beverage beverage;

   public Mocha(Beverage beverage) {
      this.beverage = beverage;
   }

   public String getDescription() {
      return beverage.getDescription() + ", Mocha";
   }
}

Another concrete decorator

public class Vanilla extends CondimentDecorator {
   Beverage beverage;

   public Vanilla(Beverage beverage) {
      this.beverage = beverage;
   }

   public String getDescription() {
      return beverage.getDescription() + ", Vanilla";
   }
}

Example

  • Decorating our Beverages
  • Java I/O

References

Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN 0-201-63361-2. http://www.dofactory.com/Patterns/PatternDecorator.aspx