Changes

Jump to: navigation, search

Decorator

6,325 bytes added, 14:33, 11 April 2007
m
Example
[[BTP600]] > [[Decorator]]
 
Allow new/additional responsibility to be added to an existing object dynamically. Decoratores provide a flexible alternative to subclassing for extending functionality.
==Introduction==
* Decorator, a [http://en.wikipedia.org/wiki/Structural_pattern structual pattern* aka Wrapper* ] 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 a the component without requiring every subclass to inherit these new qualities.* Function added at runtime through composition.* We want Each decorator class wraps a component, which means the decorator has an object instance variable that holds a reference to do something new, not its class* 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==
window[[Image:beveragedecorator.png|300 px|thumb|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(); /scrolling scenario/static abstract double size(); } [[Image:wrappingdecorator2.png|300 px|thumb|Figure 1 wrapping Decorator classes]]
// the Window interfaceLeaf classes that inherit from Beverage class interface Window public class DarkRoast extends Beverage { public void drawDarkRoast(){ description = "Dark Roast Coffee"; // draws the Window } public String getDescriptiondouble cost(){ return .99; // returns a description of the Window }
}
// implementation of a simple Window without any scrollbars public class SimpleWindow implements Window Decaf extends Beverage { public void drawDecaf() { // draw window description = "Decaf Coffee";
}
public String getDescriptiondouble cost() { return "simple window"1.05;
}
}
[[Image:beverageDecoratorWholePic.png|300 px|thumb|The decorator classesBig Picture]] Condiment Decorator class public abstract class CondimentDecorator extends Beverage { public abstract String getDescription(); }
// abstract Mocha is a concrete decorator class - note that it implements Windowcost() and getDescription() abstract public class WindowDecorator implements Window Mocha extends CondimentDecorator { protected Window decoratedWindowBeverage beverage; // the Window being decorated
public WindowDecorator Mocha(Window decoratedWindowBeverage beverage) { this.decoratedWindow beverage = decoratedWindowbeverage;
}
}
// the first concrete decorator which adds vertical scrollbar functionality class VerticalScrollBarDecorator extends WindowDecorator { public VerticalScrollBarDecorator String getDescription(Window decoratedWindow) { super return beverage.getDescription(decoratedWindow)+ ", Mocha";
}
public void drawdouble cost() { drawVerticalScrollBar(); decoratedWindow return 0.10 + beverage.drawcost();
}
}
 
Another concrete decorator
public class Vanilla extends CondimentDecorator {
Beverage beverage;
private void drawVerticalScrollBarpublic Vanilla(Beverage beverage) { // draw the vertical scrollbar this.beverage = beverage;
}
public String getDescription() {
return decoratedWindowbeverage.getDescription() + ", including vertical scrollbarsVanilla";
}
}
// the second concrete decorator which adds horizontal scrollbar functionality class HorizontalScrollBarDecorator extends WindowDecorator { public HorizontalScrollBarDecorator double cost(Window decoratedWindow) { super return 0.20 + beverage.cost(decoratedWindow);
}
}
 
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());
public void draw Beverage beverage2 = new DarkRoast() {; beverage2 = new Mocha(beverage2); beverage2 = new Mocha(beverage2); drawHorizontalScrollBar beverage2 = new Vanilla(beverage2); decoratedWindow System.out.println(beverage2.getDescription() + " $" + beverage2.drawcost());
}
}
<!--
{| align="left"
|-
[[Image:beveragedecorator.png|300 px|Beverage Decorator UML diagram]]
[[Image:wrappingdecorator.png|300 px|Figure 1 wrapping Decorator classes]]
[[Image:beverageDecoratorWholePic.png|300 px|Whole Picture]]
|}
-->
 
==Example==
[[Image:javaIOdecorator2.png|500 px|thumb|Java I/O classes]]
 
Java I/O [http://java.sun.com/javase/6/docs/api/java/io/package-frame.html API]
 
JDK 6u1 [http://www.java.net/download/jdk6/6u1/promoted/b03/jdk-6u1-ea-src-b03-jrl-19_jan_2007.jar Source] under the [http://www.java.net/jrl.csp JRL license]
 
extract: java -jar jdk-6u1-ea-src-b03-jrl-19_jan_2007.jar
 
java.io location: j2se/src/share/classes/java/io/
 
----
Abstract Component class:
public abstract class InputStream {
abstract int read();
}Concrete Component class: class FileInputStream extends InputStream { public int read(); }Decorator class: public class FilterInputStream extends InputStream { { //<span style="color:red">Local variable for storing the reference of the concrete component class</span> protected volatile InputStream in; protected FilterInputStream(InputStream in) { this.in = in; } private void drawHorizontalScrollBarpublic int read() { return in.read(); } }Concrete Decorator class: public class PushbackInputStream extends FilterInputStream { public PushbackInputStream(InputStream in, int size) { super(in); // draw <span style="color:red">Calls the horizontal scrollbarFilterInputStream class and stores the reference of InputStream</span> if (size <= 0) { throw new IllegalArgumentException("size <= 0"); } this.buf = new byte[size]; this.pos = size;
}
public String getDescriptionint read() { ensureOpen(); if (pos < buf.length) { return decoratedWindowbuf[pos++] & 0xff; } return super.getDescriptionread() + ", including horizontal scrollbars";
}
}
main program---- [[Image:mpclDecorator.png|400 px|thumb|MPCL]] Multi purpose class library (MPCL) [http://www.google.com/codesearch?hl=en&q=show:QUdC7Hs10WU:9dcfaUrTzRs:gcPYjQUkI_I&sa=N&ct=rd&cs_p=http://www.uesqlc.org/download/mpcl/mpcl-11.0.2.zip&cs_f=mpcl-11.0.2/src/java/lib/org/mpcl/nui/table/TDecoratorTableCellRenderer.java Source Code] GPL license ---- Concrete Components <br>TDecoratorTableCellRenderer: /** * Table cell renderer that decorates a delegate cell renderer. It implements * the Decorator design pattern. */ public class DecoratedWindowTest TDecoratorTableCellRenderer implements TableCellRenderer { public static void main(String[] args) { /// create a decorated Window with horizontal and vertical scrollbars Delegate table cell renderer. private TableCellRenderer tDelegateTableCellRenderer; Window decoratedWindow = new HorizontalScrollBarDecorator ( /// Table cell decorator. new VerticalScrollBarDecorator(new SimpleWindow())) private ITableCellDecorator tTableCellDecorator; // // C O N S T R U C T O R S //
/** * Builds a new instance. * @param tDELEGATE_TABLE_CELL_RENDERER The delegate table cell renderer. * @param tTABLE_CELL_DECORATOR Table cell decorator. */ public TDecoratorTableCellRenderer ( TableCellRenderer tDELEGATE_TABLE_CELL_RENDERER , ITableCellDecorator tTABLE_CELL_DECORATOR ) { tDelegateTableCellRenderer = tDELEGATE_TABLE_CELL_RENDERER; tTableCellDecorator = tTABLE_CELL_DECORATOR; }  DefaultTableCellRenderer: public class DefaultTableCellRenderer extends JLabel implements TableCellRenderer, Serializable { /** * Creates a default table cell renderer. */ print the Window's description public DefaultTableCellRenderer() { System.out.printlnsuper(); setOpaque(true); setBorder(decoratedWindow.getDescriptiongetNoFocusBorder());
}
}
TDateTableCellRenderer: public class TDateTableCellRenderer extends DefaultTableCellRenderer { /// Date format. private DateFormat tDateFormat; // // C O N S T R U C T O R S // /** * Sets the String object for the cell being rendered to value. * @param tVALUE The value for this cell; if \a tVALUE is \a null it sets the * the text value to an empty string. * @see javax.swing.table.DefaultTableCellRenderer#setValue() */ protected void setValue (Object tVALUE) { setText (( tVALUE == null ) ? "" : tDateFormat.format ((Date) tVALUE)); } TPopulationTableCellRenderer: /// Table cell renderer for \a TPopulation objects. public class TPopulationTableCellRenderer extends DefaultTableCellRenderer { /// Number format. public NumberFormat tNumberFormat; // // C O N S T R U C T O R S // /** * Sets the String object for the cell being rendered to value. * @param tVALUE The value for this cell; if \a tVALUE is \a null it sets the * the text value to an empty string. * @see javax.swing.table.DefaultTableCellRenderer#setValue() */ protected void setValue (Object tVALUE) { if ( tNumberFormat ==null) { tNumberFormat =ExampleTDecimalFormat._getPopulationInstance(); } setText (( tVALUE ==null ) ? "" : tNumberFormat.format (((TPopulation) tVALUE).intValue())); } *Decorating our Beverages //*Java I // C O N S T R U C T OR S // /// Builds a new instance. public TPopulationTableCellRenderer() { super(); setHorizontalAlignment (DefaultTableCellRenderer.RIGHT); } } // class TPopulationTableCellRenderer ==Contributions==[http://zenit.senecac.on.ca/wiki/index.php/Talk:Adapter Adapter pattern] in Eclipse
==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.
 
Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Head First Design Patterns. O`Reilly. ISBN 0-596-00712-4.
 
http://www.dofactory.com/Patterns/PatternDecorator.aspx
1
edit

Navigation menu