Decorator pattern is used to attach a new functionality to an existing object, without changing the existing class.
NOTES
In this article, we discuss the implementation of the Decorator Pattern in Java.
See the Decorator in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Decorator Pattern-
Examples
Here are some Decorator pattern implementations in Java-
Example #1: Simple Decorator
Let’s take an example of a simple and very basic decorator. To implement a basic decorator we need to use the following:
Subject Interface
// Subject.java
package com.bigboxcode.designpattern.decorator.decorator;
public interface Subject {
void operationOne();
void operationTwo();
}
JavaConcrete Subject Class
// ConcreteSubject.java
package com.bigboxcode.designpattern.decorator.decorator;
public class ConcreteSubject implements Subject {
@Override
public void operationOne() {
System.out.println("Performing Operation One(1) in Subject");
}
@Override
public void operationTwo() {
System.out.println("Performing Operation Two(2) in Subject");
}
}
JavaAbstract Decorator
// Decorator.java
package com.bigboxcode.designpattern.decorator.decorator;
public abstract class Decorator implements Subject {
protected final Subject subject;
public Decorator(Subject subject) {
this.subject = subject;
}
@Override
public void operationOne() {
this.subject.operationOne();
}
@Override
public void operationTwo() {
this.subject.operationTwo();
}
}
JavaConcrete Decorator
// ConcreteDecorator.java
package com.bigboxcode.designpattern.decorator.decorator;
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Subject subject) {
super(subject);
}
@Override
public void operationOne() {
// perform some additional operation if required
subject.operationOne();
// perform some additional operation if required
System.out.println("Performing additional operation in Concrete Decorator");
}
}
JavaDemo
// Demo.java
package com.bigboxcode.designpattern.decorator.decorator;
public class Demo {
public static void main(String[] args) {
Decorator someDecorator = new ConcreteDecorator(new ConcreteSubject());
someDecorator.operationOne();
}
}
JavaOutput
Performing Operation One(1) in Subject
Performing additional operation in Concrete Decorator
PlaintextExample #2: Data Export
Let’s take a look at how we can use the Decorator pattern which deals with data export. We have an existing class for export named SimpleExport, which implements an interface named DataExport. We want to extend the export functions capability and want to export data to CSV, Excel, and JSON.
Class Diagram
Take a look at the class diagram. Two classes are used for Decorator pattern for data export.
DataExport Interface [Existing]
// DataExport.java
package com.bigboxcode.designpattern.decorator.dataexport;
public interface DataExport {
void processData();
}
JavaSimpleExport Class [Existing]
// SimpleDataExport.java
package com.bigboxcode.designpattern.decorator.dataexport;
public class SimpleDataExport implements DataExport {
@Override
public void processData() {
System.out.println("Processing Data");
}
}
JavaMain Decorator Class [Decorator]
// DataExportDecorator.java
package com.bigboxcode.designpattern.decorator.dataexport;
public abstract class DataExportDecorator implements DataExport {
protected final DataExport dataExporter;
public DataExportDecorator(DataExport dataExporter) {
this.dataExporter = dataExporter;
}
@Override
public void processData() {
this.dataExporter.processData();
}
}
JavaCSV Decorator Class [Decorator]
// CsvDataExportDecorator.java
package com.bigboxcode.designpattern.decorator.dataexport;
public class CsvDataExportDecorator extends DataExportDecorator {
public CsvDataExportDecorator(DataExport dataExporter) {
super(dataExporter);
}
@Override
public void processData() {
dataExporter.processData();
this.processCsv();
}
private void processCsv() {
System.out.println("Processed data to CSV");
}
}
JavaExcel Decorator Class [Decorator]
// ExcelDataExportDecorator.java
package com.bigboxcode.designpattern.decorator.dataexport;
public class ExcelDataExportDecorator extends DataExportDecorator {
public ExcelDataExportDecorator(DataExport dataExporter) {
super(dataExporter);
}
@Override
public void processData() {
dataExporter.processData();
this.processExcel();
}
private void processExcel() {
System.out.println("Processed data to Excel");
}
}
JavaJSON Decorator Class [Decorator]
// JsonDataExportDecorator.java
package com.bigboxcode.designpattern.decorator.dataexport;
public class JsonDataExportDecorator extends DataExportDecorator {
public JsonDataExportDecorator(DataExport dataExporter) {
super(dataExporter);
}
@Override
public void processData() {
dataExporter.processData();
this.processJson();
}
private void processJson() {
System.out.println("Processed data to JSON");
}
}
JavaDemo
// Demo.java
package com.bigboxcode.designpattern.decorator.dataexport;
public class Demo {
public static void main(String[] args) {
DataExport csvDataExport = new CsvDataExportDecorator(new SimpleDataExport());
csvDataExport.processData();
DataExport excelDataExport = new ExcelDataExportDecorator(new SimpleDataExport());
excelDataExport.processData();
DataExport jsonDataExport = new JsonDataExportDecorator(new SimpleDataExport());
jsonDataExport.processData();
}
}
JavaOutput
The output of the demo above will be like below.
Processing Data
Processed data to CSV
Processing Data
Processed data to Excel
Processing Data
Processed data to JSON
PlaintextExample #3: UI Elements
Drawing UI elements and adding some additional properties/features can be a very good example of the Decorator Pattern. Let’s take a look at how Decorator pattern can be used for UI Elements.
UI Element Interface
// UIElement.java
package com.bigboxcode.designpattern.decorator.uielement;
public interface UIElement {
void draw();
}
JavaButton UI Element Class
// Button.java
package com.bigboxcode.designpattern.decorator.uielement;
public class Button implements UIElement {
@Override
public void draw() {
System.out.println("Drawing Button");
}
}
JavaInput Box UI Element Class
// InputBox.java
package com.bigboxcode.designpattern.decorator.uielement;
public class InputBox implements UIElement {
@Override
public void draw() {
System.out.println("Drawing Input Box");
}
}
JavaTable UI Element Class
// Table.java
package com.bigboxcode.designpattern.decorator.uielement;
public class Table implements UIElement {
@Override
public void draw() {
System.out.println("Drawing Table");
}
}
JavaAbstract UI Decorator [Decorator]
// UIDecorator.java
package com.bigboxcode.designpattern.decorator.uielement;
public abstract class UIDecorator implements UIElement {
protected final UIElement uiElement;
protected UIDecorator(UIElement uiElement) {
this.uiElement = uiElement;
}
@Override
public void draw() {
this.uiElement.draw();
}
}
JavaBorder Decorator Class [Decorator]
// BorderDecorator.java
package com.bigboxcode.designpattern.decorator.uielement;
public class BorderDecorator extends UIDecorator {
protected BorderDecorator(UIElement uiElement) {
super(uiElement);
}
@Override
public void draw() {
// Can perform any additional task anywhere in the method
super.draw();
// Write code to add border to the element
System.out.println("Adding Border to the element");
}
}
JavaBackground Decorator Class [Decorator]
// BackgroundDecorator.java
package com.bigboxcode.designpattern.decorator.uielement;
public class BackgroundDecorator extends UIDecorator {
protected BackgroundDecorator(UIElement uiElement) {
super(uiElement);
}
@Override
public void draw() {
// Can perform any additional task anywhere in the method
super.draw();
// Write code to add background to the element
System.out.println("Adding Background to the element");
}
}
JavaMargin Decorator Class [Decorator]
// MarginDecorator.java
package com.bigboxcode.designpattern.decorator.uielement;
public class MarginDecorator extends UIDecorator {
protected MarginDecorator(UIElement uiElement) {
super(uiElement);
}
@Override
public void draw() {
// Can perform any additional task anywhere in the method
super.draw();
// Write code to add margin to the element
System.out.println("Adding margin to the element");
}
}
JavaDemo
The following code demonstrates how we can use multiple decorators on a single UI Element.
// Demo.java
package com.bigboxcode.designpattern.decorator.uielement;
public class Demo {
public static void main(String[] args) {
// Draw table and add border
UIElement tableWithBorder = new BorderDecorator(new Table());
tableWithBorder.draw();
// Draw input with background and border
UIElement inputWithBorderAndBackground = new BackgroundDecorator(new BorderDecorator(new InputBox()));
inputWithBorderAndBackground.draw();
// Draw button with marin, background and border
UIElement buttonWithAllDecorator = new MarginDecorator(new BackgroundDecorator(new BorderDecorator(new Button())));
buttonWithAllDecorator.draw();
}
}
JavaOutput
Drawing Table
Adding Border to the element
Drawing Input Box
Adding Border to the element
Adding Background to the element
Drawing Button
Adding Border to the element
Adding Background to the element
Adding margin to the element
PlaintextSource Code
Use the following link to get the source code:
Example | Source Code Link |
---|---|
Example #1: Simple Decorator | GitHub |
Example #2: Data Export | GitHub |
Example #3: UI Elements | GitHub |
Other Code Implementations
Use the following links to check Decorator pattern implementation in other programming languages.