Decorator Design Pattern in Java
This article explains Decorator design pattern in java with UML class diagram. It then takes an example scenario in java and explains it with class diagram and code.
Introduction Decorator Design Pattern is a structural design pattern among the Gang Of Four(GOF) Design PatternsClick to read: Gang Of Four(GOF) Design Patterns. Being a structural design pattern, the Decorator pattern deals with how objects are composed together - here, by wrapping one object in another which adds behaviour to it. What is Decorator Design Pattern The Decorator design pattern attaches additional responsibilities to an object dynamically, at runtime, while keeping the object's interface the same. A decorator implements the same interface as the object it wraps, forwards calls to it, and adds its own behaviour before or after forwarding. Because a decorator looks exactly like the object it wraps, decorators can be stacked - a decorator can wrap another decorator - and the client cannot tell the difference. This gives a flexible alternative to subclassing: instead of a subclass for every combination of features, each feature is one small decorator class, and combinations are assembled at runtime. Scenarios in which Decorator Design Pattern can be used
Class Diagram for Decorator Design Pattern
Explanation of Decorator Design Pattern's Class Diagram
The example is a coffee shop. A beverage can have any combination of add-ons - milk, caramel, or a double shot of either - and each add-on changes both the description and the price. With subclasses, every combination would need its own class; with decorators, each add-on is one class.
Code for the classes shown in Java Example's Class Diagram
OUTPUT on running CoffeeShop.java
Explanation of Java Example's Class Diagram & Code
OUTPUT on running StreamDecorators.java
Each wrapper adds one responsibility - compression, buffering, reading primitive types - and they can be combined in any order the application needs.
Summary
In the above tutorial we understood what is Decorator design pattern and the main scenarios in which it is applicable. We then looked at the UML class diagram for Decorator Design Pattern & its explanation, a Java use case implementing the Decorator pattern for a coffee shop with its class diagram, code and output, followed by an explanation of both the class diagram & code. Lastly, we saw how the
Introduction Decorator Design Pattern is a structural design pattern among the Gang Of Four(GOF) Design PatternsClick to read: Gang Of Four(GOF) Design Patterns. Being a structural design pattern, the Decorator pattern deals with how objects are composed together - here, by wrapping one object in another which adds behaviour to it. What is Decorator Design Pattern The Decorator design pattern attaches additional responsibilities to an object dynamically, at runtime, while keeping the object's interface the same. A decorator implements the same interface as the object it wraps, forwards calls to it, and adds its own behaviour before or after forwarding. Because a decorator looks exactly like the object it wraps, decorators can be stacked - a decorator can wrap another decorator - and the client cannot tell the difference. This gives a flexible alternative to subclassing: instead of a subclass for every combination of features, each feature is one small decorator class, and combinations are assembled at runtime. Scenarios in which Decorator Design Pattern can be used
- Responsibilities added to individual objects: When behaviour should be added to some objects of a class, not all of them, and possibly at runtime - for example, buffering or compression for one particular stream.
- Too many combinations for subclassing: When features can be combined freely, so that subclassing would need a class for every combination - a "class explosion".
- Responsibilities which can be withdrawn: When features should be easy to add and remove without changing the class being decorated, which may not even be open to modification.
Componentis the interface shared by the objects being decorated and the decorators themselves.ConcreteComponentis the original object to which responsibilities are added.Decoratoris an abstract class which implementsComponentand holds a reference to aComponent- the object it wraps. Itsoperation()forwards to the wrapped component.ConcreteDecoratorAandConcreteDecoratorBextendDecorator, adding state or behaviour before or after forwarding the call.Clientworks only with theComponentinterface, so it can use a plain component or one wrapped in any number of decorators in exactly the same way.
Beverage.java - the component interface
//Beverage.java
public interface Beverage {
String description();
double cost();
}
Espresso.java - the concrete component
//Espresso.java
public class Espresso implements Beverage {
public String description() { return "Espresso"; }
public double cost() { return 120.00; }
}
BeverageDecorator.java - the abstract decorator
//BeverageDecorator.java
public abstract class BeverageDecorator implements Beverage {
protected final Beverage beverage; // the wrapped beverage
protected BeverageDecorator(Beverage beverage) {
this.beverage = beverage;
}
public String description() { return beverage.description(); }
public double cost() { return beverage.cost(); }
}
Milk.java and Caramel.java - the concrete decorators
//Milk.java
public class Milk extends BeverageDecorator {
public Milk(Beverage beverage) { super(beverage); }
public String description() { return beverage.description() + ", milk"; }
public double cost() { return beverage.cost() + 30.00; }
}
//Caramel.java
class Caramel extends BeverageDecorator {
public Caramel(Beverage beverage) { super(beverage); }
public String description() { return beverage.description() + ", caramel"; }
public double cost() { return beverage.cost() + 45.50; }
}
CoffeeShop.java (with the main() method)
//CoffeeShop.java
public class CoffeeShop {
static void serve(Beverage b) {
System.out.printf("%-40s Rs. %.2f%n", b.description(), b.cost());
}
public static void main(String[] args) {
serve(new Espresso()); // plain
serve(new Milk(new Espresso())); // one decorator
serve(new Caramel(new Milk(new Espresso()))); // decorators stacked
serve(new Caramel(new Caramel(new Milk(new Espresso())))); // the same decorator twice
}
}
Espresso Rs. 120.00 Espresso, milk Rs. 150.00 Espresso, milk, caramel Rs. 195.50 Espresso, milk, caramel, caramel Rs. 241.00
Beverageis the component interface, andEspressothe concrete component.BeverageDecoratoris the decorator: it implementsBeverageand wraps anotherBeverage, forwarding to it by default.MilkandCaramelare concrete decorators. Each calls the wrapped beverage and adds its own part -", milk"to the description, Rs. 30 to the cost.- In
new Caramel(new Milk(new Espresso())), a call tocost()goes toCaramel, which callsMilk, which callsEspresso; the results are added on the way back.serve()cannot tell a decorated beverage from a plain one. - Two classes of add-ons produce any combination, including the same add-on twice - something subclassing could not express without a class for every case.
java.io package. InputStream is the component; FileInputStream and ByteArrayInputStream are concrete components; and FilterInputStream is the decorator base class, extended by BufferedInputStream, DataInputStream, GZIPInputStream and others -
java.io streams decorating each other
//StreamDecorators.java
import java.io.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class StreamDecorators {
public static void main(String[] args) throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
// DataOutputStream decorates GZIPOutputStream, which decorates the byte array stream
try (DataOutputStream out = new DataOutputStream(new GZIPOutputStream(bytes))) {
out.writeUTF("Decorator pattern");
out.writeInt(1994);
}
System.out.println("Compressed size: " + bytes.size() + " bytes");
// Reading back with the same decorators, in the same order
try (DataInputStream in = new DataInputStream(new BufferedInputStream(
new GZIPInputStream(new ByteArrayInputStream(bytes.toByteArray()))))) {
System.out.println("Read back: " + in.readUTF() + ", " + in.readInt());
}
}
}
Compressed size: 43 bytes Read back: Decorator pattern, 1994
Collections.unmodifiableList() and Collections.synchronizedList() are decorators too: they wrap a list and change the behaviour of its methods.
java.io streams are built on the Decorator pattern. This concludes the tutorial on Decorator design pattern.Gang of Four (GOF) Design Patterns on JavaBrahman
Creational Patterns: Abstract Factory PatternAbstract Factory Design Pattern in Java Builder PatternBuilder Design Pattern in Java Factory Method PatternFactory Method Design Pattern in Java Prototype PatternPrototype Design Pattern in Java Singleton PatternSingleton Design Pattern in Java
Structural Patterns: Adapter PatternAdapter Design Pattern in Java Bridge PatternBridge Design Pattern in Java Composite PatternComposite Design Pattern in Java Decorator PatternDecorator Design Pattern in Java Facade PatternFacade Design Pattern in Java Flyweight PatternFlyweight Design Pattern in Java Proxy PatternProxy Design Pattern in Java
Behavioral Patterns: Chain of Responsibility PatternChain of Responsibility Design Pattern in Java Command PatternCommand Design Pattern in Java Interpreter PatternInterpreter Design Pattern in Java Iterator PatternIterator Design Pattern in Java Mediator PatternMediator Design Pattern in Java Memento PatternMemento Design Pattern in Java Observer PatternObserver Design Pattern in Java State PatternState Design Pattern in Java Strategy PatternStrategy Design Pattern in Java Template Method PatternTemplate Method Design Pattern in Java Visitor PatternVisitor Design Pattern in Java
Analysis of Patterns: Strategy vs State PatternStrategy Design Pattern versus State Design Pattern GOF Patterns OverviewGOF / Gang of Four Design Patterns in Java
Creational Patterns: Abstract Factory PatternAbstract Factory Design Pattern in Java Builder PatternBuilder Design Pattern in Java Factory Method PatternFactory Method Design Pattern in Java Prototype PatternPrototype Design Pattern in Java Singleton PatternSingleton Design Pattern in Java
Structural Patterns: Adapter PatternAdapter Design Pattern in Java Bridge PatternBridge Design Pattern in Java Composite PatternComposite Design Pattern in Java Decorator PatternDecorator Design Pattern in Java Facade PatternFacade Design Pattern in Java Flyweight PatternFlyweight Design Pattern in Java Proxy PatternProxy Design Pattern in Java
Behavioral Patterns: Chain of Responsibility PatternChain of Responsibility Design Pattern in Java Command PatternCommand Design Pattern in Java Interpreter PatternInterpreter Design Pattern in Java Iterator PatternIterator Design Pattern in Java Mediator PatternMediator Design Pattern in Java Memento PatternMemento Design Pattern in Java Observer PatternObserver Design Pattern in Java State PatternState Design Pattern in Java Strategy PatternStrategy Design Pattern in Java Template Method PatternTemplate Method Design Pattern in Java Visitor PatternVisitor Design Pattern in Java
Analysis of Patterns: Strategy vs State PatternStrategy Design Pattern versus State Design Pattern GOF Patterns OverviewGOF / Gang of Four Design Patterns in Java