Difference between revisions of "Decorator"

From CDOT Wiki
Jump to: navigation, search
(Sample Code)
(Example)
Line 129: Line 129:
  
 
----
 
----
 +
 +
public abstract class InputStream implements Closeable {
 +
 +
 +
public
 +
class FilterInputStream extends InputStream {
 +
{
 +
 +
public
 +
class FileInputStream extends InputStream
 +
{
  
 
==References==
 
==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.
 
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
 
http://www.dofactory.com/Patterns/PatternDecorator.aspx

Revision as of 11:53, 1 March 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 a coffee shop ordering service where beverages can be decorated with different kinds of condiments. By using the Decorator pattern one can get their beverage just right and the cost can be easily calculated for every added condiment. Adding new beverages/condiments is easy too, just by creating the new class and changing the menu.

Sample Code

Beverage Decorator UML diagram

Beverage is the abstract component class

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

   public String getDescription() {
      return description;
   }

   public abstract double cost();
   //static abstract double size();
}
Figure 1 wrapping Decorator classes

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;
   }
}
The Big Picture

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";
   }
   
   public double cost() {
    	return 0.10 + beverage.cost();
   }
}

Another concrete decorator

public class Vanilla extends CondimentDecorator {
   Beverage beverage;

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

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

   public double cost() {
    	return 0.20 + beverage.cost();
   }
}

The main: Here we are creating a new Decaf object with no condiments and printing its description and cost. The second beverage is created and we call it DarkRoast, we add two shots of Mocha and a shot of vanilla. Note how the beverage object is passed into the condiment decorator, this is how wrapping works. DarkRoast is wrapped with Mocha first, the Mocha object stores a reference to the beverage passed in. This is demonstrated in Figure 1.

public class StarbuzzCoffee {
   public static void main(String args[]) {
      Beverage beverage = new Decaf();
      System.out.println(beverage.getDescription() + " $" + beverage.cost());

      Beverage beverage2 = new DarkRoast();
      beverage2 = new Mocha(beverage2);
      beverage2 = new Mocha(beverage2);
      beverage2 = new Vanilla(beverage2);
      System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
   }
}

Example

Java I/O classes

Java I/O

JDK 6u1 Source under the JRL license

jdk-6u1-ea-src-b03-jrl-19_jan_2007.jar

extract: java -jar jdk-6u1-ea-src-b03-jrl-19_jan_2007.jar

java.io location: j2se/src/share/classes/java/io/


public abstract class InputStream implements Closeable {


public
class FilterInputStream extends InputStream {
{
public
class FileInputStream extends InputStream
{

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