tl  tr
  Home | Tutorials | Articles | Videos | Products | Tools | Search
Interviews | Open Source | Tag Cloud | Follow Us | Bookmark | Contact   
 Design Patterns > Java Design Patterns > Decorator

Decorator 

Decorator pattern comes under Structural design pattern. Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Behaviour & Advantages

  • Dynamically enhances the functionality of an object.
  • Supports dynamic functionality through wrapping.
  • Client may chain the dynamic features as needed at runtime.
Participants
  • Component
    Abstract interface for objects that can have responsibilities added to them dynamically.
  • Concrete Component
    An implementation of Component.
  • Decorator
    An implementation of Component which holds a reference to Concrete Component.
  • Concrete Decorator
    Concrete Decorator extends Decorator and enhances the functionality of Component.

This example shows a simple label which is decorated with various borders. Here ILabel interface acts as Component and SimpleLabel class acts as Concrete Component. Classes UpperCaseLabel, TopBorderedLabel and BottomBorderedLabel are Concrete Decorators extended from Decorator class LabelDecorator.

Label Component interface is shown below,

File Name  :  
com/bethecoder/tutorials/dp/decorator/ILabel.java 
   
package com.bethecoder.tutorials.dp.decorator;

public interface ILabel {

  /**
   * Print this label.
   */
  public void print();
  
  /**
   * Get label text. 
   */
  public String getText();
  
  /**
   * Set label text. 
   */
  public void setText(String text);
}
   

Label Concrete Component implementation.

File Name  :  
com/bethecoder/tutorials/dp/decorator/SimpleLabel.java 
   
package com.bethecoder.tutorials.dp.decorator;

public class SimpleLabel implements ILabel {

  private String label;
  
  public SimpleLabel(String label) {
    this.label = label;
  }
  
  @Override
  public void print() {
    System.out.println(label);
  }

  @Override
  public String getText() {
    return label;
  }

  @Override
  public void setText(String text) {
    this.label = text;
  }
}
   

Label Decorator implementation is shown below,

File Name  :  
com/bethecoder/tutorials/dp/decorator/LabelDecorator.java 
   
package com.bethecoder.tutorials.dp.decorator;

public abstract class LabelDecorator implements ILabel {

  private ILabel label;
  
  public LabelDecorator(ILabel label) {
    this.label = label;
  }

  @Override
  public void print() {
    label.print();
  }

  @Override
  public String getText() {
    return label.getText();
  }

  @Override
  public void setText(String text) {
    label.setText(text);
  }
}
   

UpperCaseLabel Concrete Decorator implementation.

File Name  :  
com/bethecoder/tutorials/dp/decorator/UpperCaseLabel.java 
   
package com.bethecoder.tutorials.dp.decorator;

public class UpperCaseLabel extends LabelDecorator {

  public UpperCaseLabel(ILabel label) {
    super(label);
    setText(label.getText().toUpperCase());
  }
}
   

TopBorderedLabel Concrete Decorator implementation.

File Name  :  
com/bethecoder/tutorials/dp/decorator/TopBorderedLabel.java 
   
package com.bethecoder.tutorials.dp.decorator;

import java.util.Arrays;

public class TopBorderedLabel extends LabelDecorator {

  public TopBorderedLabel(ILabel label) {
    super(label);
  }

  @Override
  public void print() {
    char [] topBorder = new char[getText().length()];
    Arrays.fill(topBorder, '*');
    
    System.out.println(String.valueOf(topBorder));
    super.print();
  }

}
   

BottomBorderedLabel Concrete Decorator implementation.

File Name  :  
com/bethecoder/tutorials/dp/decorator/BottomBorderedLabel.java 
   
package com.bethecoder.tutorials.dp.decorator;

import java.util.Arrays;

public class BottomBorderedLabel extends LabelDecorator {

  public BottomBorderedLabel(ILabel label) {
    super(label);
  }

  @Override
  public void print() {
    char [] bottomBorder = new char[getText().length()];
    Arrays.fill(bottomBorder, '*');
    
    super.print();
    System.out.println(String.valueOf(bottomBorder));
    
  }

}
   

We can see that label component is wrapped with Concrete Decorators in each step as a chain. The output rendered changes as we wrap with each Concrete Decorator. Decorator pattern usage is shown below,

File Name  :  
com/bethecoder/tutorials/dp/decorator/Test.java 
   
package com.bethecoder.tutorials.dp.decorator;


public class Test {

  /**
   @param args
   */
  public static void main(String[] args) {

    //Label step by step chaining
    ILabel label = new SimpleLabel("be the coder");
    label.print();
    
    System.out.println();
    label = new UpperCaseLabel(label);
    label.print();
    
    System.out.println();
    label = new TopBorderedLabel(label);
    label.print();
    
    System.out.println();
    label = new BottomBorderedLabel(label);
    label.print();
    
    //Label direct chaining
    System.out.println();
    label = new TopBorderedLabel(
          new BottomBorderedLabel(
              new SimpleLabel("Decorator Pattern")));
    label.print();
    
  }

}
   

It gives the following output,
be the coder

BE THE CODER

************
BE THE CODER

************
BE THE CODER
************

*****************
Decorator Pattern
*****************



 
  


  
bl  br