Samuel Lee

Decorator Pattern

Samuel Lee, George Luo


Decorator Pattern
Abstract

As more programs use the object oriented technology, the design of object oriented software becomes more important than ever. Software design pattern allows developers to reuse successful design and architecture more easily. In this paper, a type of software design pattern called Decorator is introduced.

Introduction

Design pattern provides a solution to a problem that occurs over and over again within a specific context and by identifying the patterns in the software design, it allows us to reuse the same structure on similar problems and also help software developers to communicate more efficiently through a common knowledge. One type of a structural pattern is the Decorator pattern. By being a structural pattern which means that Decorator is mostly concerned with how objects and classes are composed to form this structure. The main intention for Decorator is to provide a more flexible and dynamic way of adding functionality to an object when comparing to inheritance or subclassing approach.

Definition

In the inheritance approach, we extend the responsibility of a particular class by using subclasses. Even though this approach is quick and easy but it does not provide flexibility because there is not an option of extending the functionality only to an object, instead of whole class. A more flexible way of extending a responsibility is to use the Decorator pattern where the component or object is enclosed in another Decorator object and at run time this Decorator object will add extra responsibility to what the enclosed object already provide. One other evidence that the Decorator is more flexible than the inheritance approach is that decorators can be chained together dynamically. Each Decorator provide extra responsibility to an object and by chaining them together (a Decorator enclose another Decorator) it will provide an unlimited number of extra functionalities.

Another way of looking at the Decorator pattern is that Decorator changes the skin of an object without changing the internal guts of an object. For example, the cell phones today allow us to change the faceplate or even the antenna of the cell phone to make it more stylish looking or a flashing light will appear on the antenna when a call is received. The faceplate and antenna are the added feature (additional responsibility in object) of the cell phone where a user can decide to change it when ever they want (at run time), and unlike the chips, speakers or number keys are set statically at the factory. So software decorators are like cell phone plates or antenna, where it encapsulates some functionality that can be snap onto or add on to an existing object.

The Decorator is also known as the Wrapper because it extends the functionality by wrapping itself on top of an object.

 

Decorator Pattern Structure

 

        Figure 1: Decorator Pattern Structure (Kremer, 2003)

By looking at the structure of the decorator pattern, we can clearly define the pattern into four classes. Here is the explanation for each of the class:

Now we use an example to illustrate the above definition.

               Figure 2: Decorator Pattern Structure Example (Duell, 1999)

On this diagram, the Visual Component corresponds to the Component. The Painting corresponds to the Concrete Component. The frame and matte correspond to the Concrete Decorator.

We know painting (Concrete Component) can be hung on a wall with or without frames (Concrete Decorators). Normally, painting will be framed and matted before hanging. Just Adding or removing frames and mattes to or from an individual painting provide more flexibility than requiring all paintings to have the same frame. The Decorators are separate from Component.

Motivation

It was mentioned in the paragraphs above, one way to add responsibility is inheritance. But it is inflexible and the additional responsibility is made statically. Sometimes we just need to add responsibilities in an individual objects, not to entire class which inheritance does. A more flexible way is to enclose an object in the component that adds the functionality and the enclosing object is called a decorator.

A Decorator must conform to the interface of the component and because of this regulation; the Decorator is also transparent to the component. When a Decorator queries a component, an additional action may be performed before or after querying. The transparency character of the Decorator pattern lets you nest Decorators recursively. A conclusion to the Decorator pattern is that Decorators can be added in anywhere of a component. In general, clients don’t need to worry about how the decorator adds responsibilities, it is Concrete Decorators’ responsibility to extend and implement all the extra functionalities.

Suppose we have a TextView object (Concrete Component) that displays text in a window, but it has no scroll bars and border on it by default. When we are going to add them in the window, we can apply ScrollDecorator and BorderDecorator (Concrete Decorators) to do these. Suppose we have defined a VisualWindow (Component) as the abstract class for the TextView up front. It defines their drawing and event handling interface. The ScrollDecorator and BorderDecorator are subclasses of decorator. The Decorator class simply forwards drawing requests to VisualWindow. Decorator subclasses: ScrollDecorator and BorderDecorator. They will add scroll bar and border in the VisualWindow. An example of the Decorator being called in a nested way looks like this:

VisaulWindow.addComponent(new BorderDecorator(new ScrollDecorator(new TextView())));

 

Implementation

Before we actually go into detail on some of the pitfalls, hints or techniques that we should be aware of in terms of applying Decorator pattern, let's take a look at the example (Whitney, 2001) below.

If we want to implement text view with the following features:

  • side scroll bar
  • Bottom scroll bar
  • 3D border
  • Flat border
  • With all the combination of features, it will produce up to 12 different options:

  • TextView
  • TextViewWithNoBorder&SideScrollbar
  • TextViewWithNoBorder&BottomScrollbar
  • TextViewWithNoBorder&Bottom&SideScrollbar
  • TextViewWith3DBorder
  • TextViewWith3DBorder&SideScrollbar
  • TextViewWith3DBorder&BottomScrollbar
  • TextViewWith3DBorder&Bottom&SideScrollbar
  • TextViewWithFlatBorder
  • TextViewWithFlatBorder&SideScrollbar
  • TextViewWithFlatBorder&BottomScrollbar
  • TextViewWithFlatBorder&Bottom&SideScrollbar
  • One of the solutions is to implement this example with object composition.

       Figure 3: Implement TextView using Object Composition (Whitney, 2001)

    The java code for this example may be written as:
    class TextView {
       Border aBorder;
       ScrollBar verticalBar;
       ScrollBar horizontalBar;
       public void draw() {
          aBorder.draw();
          verticalBar.draw();
          horizontalBar.draw();
          code to draw self }
       etc.
    }

    By using this approach, we can see that TextView have Border and Scrollbar objects encapsulated inside of the class which means TextView knows everything about Border, Scrollbar and all the variations. Therefore, it is harder for us to add extra features by using this approach since for every features that we add, TextView will need to know about it and that requires modifying the TextView class.

    Let’s take a look at the other solution by using the Decorator approach.

         Figure 5: Decorator Runtime Structure (Whitney, 2001)

    In this example (figure 4) we can see that TextView is a subclass of the VisualComponent class and it does not contain any Border or Scrollbar object. From the runtime structure of the Decorator pattern (figure 5), the TextView object (aTextView) is enclosed in the Concrete Decorator (aScrokkDecorator) and then this object is enclosed in another Concrete Decorator (aBorderDecorator). As mentioned before, this chaining of Decorators and enclosing the object inside the Decorators will add extra responsibilities to the TextView object transparently, which means that by adding extra responsibilities will not affect TextView class at all.

    Here are some of the things to remember or consider when implementing your code using Decorator pattern:

    Comparison of Decorator vs. Strategy Pattern

    Even though both Decorators and Strategies add responsibilities to an object, there are some differences on how extra responsibilities are implemented.

    The Decorator pattern only changes the skin of a component, which means that the component doesn't have to know anything about its Decorators. Hence, the Decorators are transparent to the component. As in the Strategy pattern, the component has reference to the corresponding strategies and that is how it knows all the possible extensions. The advantage of the Strategy pattern is that strategy can have a specialized interface, which means that it can have heavyweight component class but the Strategy class can be lightweight. But the short coming of the Strategy pattern is that when ever we need to add new responsibilities we will need to modify the component class itself. The figures below illustrate both patterns in the run time structure.

          Figure 6: Decorator Pattern Runtime Structure (Gamma, 1995)

          Figure 7: Strategy Pattern Runtime Structure (Gamma, 1995)

    Examples

    Here is a java code example (Kuhl, 2000) that illustrates the Decorator pattern.

    // An abstract VisualComponent class that defines the interface
    abstract class VisualComponent( ) {
       public void Draw( );
       public void Resize( );
       ...
    }

    // An abstract Decorator class
    // Subclass of VisualComponent and it conforms to the VisualComponent interface
    abstract class Decorator extends VisualComponent {
       private VisualComponent component;
       public Decorator (VisualComponent comp) {
          this.component = comp;
       } // constructor
       public Draw( ) {
        component.Draw( );
        } // Draw
       public Resize( ) {
          component.resize( );
       }// Resize
       ...
    }

    //A concrete decorator class that is a subclass of the abstract decorator class
    //It still needs to conform to the interface but it added extra responsibility
    //This class implements the border functionality
    class BorderDecorator extends Decorator {
       private int width;
       public BorderDecorator(VisualComponent comp, int BorderWidth) {
          super(comp); // call constructor of parent class
          this.width = BorderWidth;
       } // Constructor

       private void DrawBorder {
          ... // code to implement Draw Border method
       } // DrawBorder

       public Draw( ) {
          super.Draw( );
          DrawBorder(width);
       } // Draw
       ...
    }

    //A concrete decorator class that is a subclass of the abstract decorator class
    //It still needs to conform to the interface but it added extra responsibility
    //This class implements the scroll bar functionality
    class ScrollDecorator extends Decorator {
       private int position = 0;
       public ScrollDecorator(VisualComponent comp) {
          super(comp);    // call constructor of parent class
       } // Constructor
       private void ScrollTo(int newposition) {
          ... // code to implement ScrollTo method
       } // ScrollTo
       private void DrawScroll( ) {
          … // code to implement DrawScroll method
       } // DrawScroll
       public Draw( ) {
          super.Draw( );
          DrawScroll;
       } // Draw
       ...
    }

    //The client – the main program
    //A component object is instantiated and enclosed in the decorator
    public class Client{
       public static void main(String args[]){
          VisualComponent bstext = new BorderDecorator(new ScrollDecorator (new TextView()));
          bstext.draw();
       }
    }

                 Figure 8: Decorator Pattern Example (Kuhl, 2000)

    In figure 8 it illustrate how a decorator adds the functionality and forwards the rest of the request to the enclosed component object to be handled.

    Consequences

    Here are some of the benefits and liabilities of applying Decorator pattern:

    Advantage

    Shortcoming
    Know uses


    References
    1. Gamma, E., Helm, R., Johnson, R. & Vlissides, J. (1995). Design Patterns: Elements of Reusable Object-Oriented Software. Reading Mass., Addison Wesley.
    2. Kremer, R. (2003), Programming Patterns Overview, SENG 609.04 Design Patterns. SERN, University of Calgary. http://sern.ucalgary.ca/courses/seng/609.04/W03/notes/index.html
    3. Duell, Michael (1999), Examples to Accompany: Design Patterns Elements of Reusable Object-Oriented Software, AG Communication Systems. http://www.agcs.com/supportv2/techpapers/patterns/papers/tutnotes
    4. Whitney, Roger (2001), Decorator, Chain of Responsibility, OO Recursion, San Diego State University. http://www.eli.sdsu.edu/courses/spring01/cs635/notes/decorator/decorator.html
    5. Kuhl, John (2000), Software Engineering - Architecture & Design of Software Systems, Department of Electrical and Computer Engineering, University of Iowa http://www.icaen.uiowa.edu/~kuhl/SoftEng/Slides1.pdf
    6. Geary, David (2001), Decorate your Java code - A look at the Decorator design pattern, Java World. http://www.javaworld.com/javaworld/jw-12-2001/jw-1214-designpatterns_p.html

    The University of Calgary
    back to previous page
    back
    Up to page above
    up
    forward to next page
    forward
    Software Engineering Research Network

    mail to Samuel Lee

    SENG 609.04

    Last Modified Date: January 25, 2003