Decorator pattern is used to attach a new functionality to an existing object, without changing the existing class.
This article demonstrates Decorator pattern implementations in Java. Check the following examples.
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();
}
Concrete 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");
}
}
Abstract 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();
}
}
Concrete 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");
}
}
Demo
// 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();
}
}
Output
Performing Operation One(1) in Subject
Performing additional operation in Concrete Decorator
Example #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();
}
SimpleExport Class [Existing]
// SimpleDataExport.java
package com.bigboxcode.designpattern.decorator.dataexport;
public class SimpleDataExport implements DataExport {
@Override
public void processData() {
System.out.println("Processing Data");
}
}
Main 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();
}
}
CSV 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");
}
}
Excel 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");
}
}
JSON 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");
}
}
Demo
// 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();
}
}
Output
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
Example #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();
}
Button 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");
}
}
Input 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");
}
}
Table 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");
}
}
Abstract 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();
}
}
Border 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");
}
}
Background 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");
}
}
Margin 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");
}
}
Demo
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();
}
}
Output
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
Source 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.