Decorator

From CDOT Wiki
Revision as of 17:56, 26 February 2007 by Dtolj (talk | contribs) (Motivation)
Jump to: navigation, search

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 requireing 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

window/scrolling scenario

// the Window interface
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
class SimpleWindow implements Window {
   public void draw() {
       // draw window
   }

   public String getDescription() {
       return "simple window";
   }
}

The decorator classes

// abstract decorator class - note that it implements Window
abstract class WindowDecorator implements Window {
   protected Window decoratedWindow; // the Window being decorated

   public WindowDecorator (Window decoratedWindow) {
       this.decoratedWindow = decoratedWindow;
   }
}

// the first concrete decorator which adds vertical scrollbar functionality
class VerticalScrollBarDecorator extends WindowDecorator {
   public VerticalScrollBarDecorator (Window decoratedWindow) {
       super(decoratedWindow);
   }

   public void draw() {
       drawVerticalScrollBar();
       decoratedWindow.draw();
   }

   private void drawVerticalScrollBar() {
       // draw the vertical scrollbar
   }

   public String getDescription() {
       return decoratedWindow.getDescription() + ", including vertical scrollbars";
   }
} 

// the second concrete decorator which adds horizontal scrollbar functionality
class HorizontalScrollBarDecorator extends WindowDecorator {
   public HorizontalScrollBarDecorator (Window decoratedWindow) {
       super(decoratedWindow);
   }

   public void draw() {
       drawHorizontalScrollBar();
       decoratedWindow.draw();
   }

   private void drawHorizontalScrollBar() {
       // draw the horizontal scrollbar
   }

   public String getDescription() {
       return decoratedWindow.getDescription() + ", including horizontal scrollbars";
   }
}

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());
   }
}

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