Design Pattern: Decorator Pattern in Java

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:

Other Code Implementations

Use the following links to check Decorator pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.