Design Pattern: Decorator Pattern

Summary

Pattern NameDecorator Pattern
Pattern TypeStructural Pattern
ScopeObject
TaglineAdditional responsibility to individual objects without affecting other objects
Use casesWhen we want to attach additional responsibility/functionality
to individual objects and not to the class
Related PatternsAdapter
Proxy
Strategy
Difficulty LevelEasy
Implementations

Definition

In Decorator design pattern, our target is to add some new functionality without affecting the existing object.

Say, there is an existing class that is responsible for printing a UI element (like a Button or a Table). Later we need the ability to add a border or text color to that element.

We can add new properties and functions to that existing class and introduce those properties. But that will violate the Open-Close principle of the SOLID principle.

So we can use the Decorator pattern and introduce those new properties and functions. The decorator pattern will add one or more new Classes which will contain the existing functionality of the existing object and will also contain new functionalities. That way these new properties will not be added to every object. Only the new decorator class(es) objects will have these new functionalities.

You can think of the decorator as a new skin/layer over the existing object. The actual object exists as it is, by using Decorator pattern we are just adding classes that will wrap the existing class and add new functionalities on top of that.

Implementation

A simple implementation of Decorator pattern will look like the diagram below.

Here are the steps you need to follow while implementing the Decorator design pattern.

  1. Create an Abstract class that implements the same interface as the actual object.
  2. This main Abstract class should set the actual object in the constructor.
  3. Introduce the decorator classes which extend the Main decorator abstract class.
  4. In the new decorator class call the constructor abstract class constructor so that the main class object can be set here.
  5. In the new decorator class call the functions from the actual class, and include additional functionality with that existing functionality.

Examples

The following examples demonstrate how can we implement Decorator pattern in different use cases.

Example #1: Data Export

We are considering a data export operation for this example of Decorator pattern.

We have an existing class that can handle simple data export (fetching data and exporting in simple text format). Later we need to implement export as CSV, Excel, and JSON.

We can implement Decorator pattern to implement these new functionalities. Check the following implementation.

DataExport Interface

interface DataExport

   fuction processData()

end interface

SimpleExport Class

class SimpleDataExport implements DataExport

   function processData() 
       // some operation to fetch data and handling
   end function

end class

Main Decorator Class

abstract class DataExportDecorator implements DataExport

   dataExporter: DataExport

    constructor(dataExporterParam: DataExport)
        dataExporter = dataExporterParam
    end constructor

    function processData()
        dataExporter.processData()
    end function

end class

CSV Decorator Class

class CsvDataExportDecorator extends DataExportDecorator
    
    constructor(dataExporterParam: DataExport)
        // call parent constructor
        super(dataExporterParam)
    end constructor

    
    function processData() 
        dataExporter.processData()
        processCsv()
    end function

    function processCsv()
        // process data to CSV
    end function

end class

Excel Decorator Class

class ExcelDataExportDecorator extends DataExportDecorator
    
    constructor(dataExporterParam: DataExport)
        // call parent constructor
        super(dataExporterParam)
    end constructor

    
    function processData() 
        dataExporter.processData()
        processExcel()
    end function

    function processExcel()
        // process data to Excel
    end function

end class

JSON Decorator Class

class JsonDataExportDecorator extends DataExportDecorator
    
    constructor(dataExporterParam: DataExport)
        // call parent constructor
        super(dataExporterParam)
    end constructor

    
    function processData() 
        dataExporter.processData()
        processJson()
    end function

    function processJson()
        // process data to JSON
    end function

end class

Usage

csvDataExport = new CsvDataExportDecorator(new SimpleDataExport())
csvDataExport.processData()

excelDataExport = new ExcelDataExportDecorator(new SimpleDataExport())
excelDataExport.processData()

jsonDataExport = new JsonDataExportDecorator(new SimpleDataExport())
jsonDataExport.processData()

Code Implementations

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

Leave a Comment