Decorator Design Pattern
Decorator Design Pattern is a structural pattern that lets you dynamically add behavior to individual objects without changing other objects of the same class. It uses decorator classes to wrap concrete components, making functionality more flexible and reusable.
Let's understand this with the help of diagram:

The diagram shows a Pizza (base component) wrapped with Capsicum and then Cheese Burst (decorators). Each adds its own cost via getCost(), so the final price = Pizza + Capsicum + Cheese Burst. This illustrates how the Decorator Pattern layers extra behavior dynamically.
Key Features of the Decorator Pattern
- Dynamic Behavior Addition: Add or remove responsibilities at runtime without modifying the original object.
- Open-Closed Principle (OCP): Extend object behavior without altering existing code.
- Composition over Inheritance: Combine multiple behaviors without creating a rigid class hierarchy.
- Reusable Decorators: Same decorators can be applied to different objects.
- Flexible and Scalable: Easily add new features without touching existing code.
Real-World Examples
- Coffee Shop Application: Customers can customize their coffee with add-ons like milk, sugar or whipped cream. Each add-on is a decorator dynamically applied to the coffee object.
- Video Streaming Platforms: Videos can have subtitles, audio enhancements, multiple resolutions or language options, all added as decorators.
- Text Processing Applications: A plain text object can be wrapped with BoldDecorator, ItalicDecorator or UnderlineDecorator to apply multiple formatting styles.
- Java I/O Library: Classes like FileInputStream can be wrapped by BufferedInputStream or DataInputStream to add additional functionality without changing the core class.
Key Components of the Decorator Design Pattern
- Component Interface: Defines common operations for components and decorators.
- Concrete Component: Core object with basic functionality.
- Decorator: Abstract wrapper that holds a
Componentreference and adds behavior. - Concrete Decorator: Specific decorators that extend functionality of the component.
Example of Decorator Design Pattern
Below is the problem statement to understand the Decorator Design Pattern:
Suppose we are building a coffee shop application where customers can order different types of coffee. Each coffee can have various optional add-ons such as milk, sugar, whipped cream, etc. We want to implement a system where we can dynamically add these add-ons to a coffee order without modifying the coffee classes themselves.
Using the Decorator Pattern allows us to add optional features (add-ons) to coffee orders dynamically without altering the core coffee classes. This promotes code flexibility, scalability and maintainability as new add-ons can be easily introduced and combined with different types of coffee orders.

Lets Breakdown the code into component wise code:
1. Component Interface(Coffee)
- This is the interface Coffee representing the component.
- It declares two methods getDescription() and getCost() which must be implemented by concrete components and decorators.
#include <string>
class Coffee {
public:
virtual std::string getDescription() = 0;
virtual double getCost() = 0;
};
// Coffee.java
public interface Coffee {
String getDescription();
double getCost();
}
from abc import ABC, abstractmethod
class Coffee(ABC):
@abstractmethod
def getDescription(self):
pass
@abstractmethod
def getCost(self):
pass
class Coffee {
getDescription() {
throw new Error("Method not implemented.");
}
getCost() {
throw new Error("Method not implemented.");
}
}
2. ConcreteComponent(PlainCoffee)
- PlainCoffee is a concrete class implementing the Coffee interface.
- It provides the description and cost of plain coffee by implementing the getDescription() and getCost() methods.
/*package whatever //do not write package name here */
#include <iostream>
int main() {
std::cout << "GFG!" << std::endl;
return 0;
}
/*package whatever //do not write package name here */
import java.io.*;
class GFG {
public static void main (String[] args) {
System.out.println("GFG!");
}
}
/*package whatever //do not write package name here */
# Python3 code
print("GFG!")
/*package whatever //do not write package name here */
// JavaScript code
console.log('GFG!');
3. Decorator(CoffeeDecorator)
- CoffeeDecorator is an abstract class implementing the Coffee interface.
- It maintains a reference to the decorated Coffee object.
- The getDescription() and getCost() methods are implemented to delegate to the decorated coffee object.
#include <string>
#include <iostream>
class Coffee {
public:
virtual std::string getDescription() = 0;
virtual double getCost() = 0;
};
class PlainCoffee : public Coffee {
public:
std::string getDescription() override {
return "Plain Coffee";
}
double getCost() override {
return 2.0;
}
};
// PlainCoffee.java
public class PlainCoffee implements Coffee {
@Override
public String getDescription() {
return "Plain Coffee";
}
@Override
public double getCost() {
return 2.0;
}
}
from abc import ABC, abstractmethod
class Coffee(ABC):
@abstractmethod
def getDescription(self):
pass
@abstractmethod
def getCost(self):
pass
class PlainCoffee(Coffee):
def getDescription(self):
return "Plain Coffee"
def getCost(self):
return 2.0
class Coffee {
getDescription() {
throw new Error("Method not implemented.");
}
getCost() {
throw new Error("Method not implemented.");
}
}
class PlainCoffee extends Coffee {
getDescription() {
return "Plain Coffee";
}
getCost() {
return 2.0;
}
}
4. ConcreteDecorators(MilkDecorator,SugarDecorator)
- MilkDecorator and SugarDecorator are concrete decorators extending CoffeeDecorator.
- They override getDescription() to add the respective decorator description to the decorated coffee's description.
- They override getCost() to add the cost of the respective decorator to the decorated coffee's cost.
#include <string>
#include <iostream>
class Coffee {
public:
virtual std::string getDescription() const = 0;
virtual double getCost() const = 0;
};
class CoffeeDecorator : public Coffee {
protected:
Coffee* decoratedCoffee;
public:
CoffeeDecorator(Coffee* coffee) : decoratedCoffee(coffee) {}
virtual std::string getDescription() const override {
return decoratedCoffee->getDescription();
}
virtual double getCost() const override {
return decoratedCoffee->getCost();
}
};
class MilkDecorator : public CoffeeDecorator {
public:
MilkDecorator(Coffee* coffee) : CoffeeDecorator(coffee) {}
std::string getDescription() const override {
return CoffeeDecorator::getDescription() + ", Milk";
}
double getCost() const override {
return CoffeeDecorator::getCost() + 0.5;
}
};
class SugarDecorator : public CoffeeDecorator {
public:
SugarDecorator(Coffee* coffee) : CoffeeDecorator(coffee) {}
std::string getDescription() const override {
return CoffeeDecorator::getDescription() + ", Sugar";
}
double getCost() const override {
return CoffeeDecorator::getCost() + 0.2;
}
};
public interface Coffee {
String getDescription();
double getCost();
}
public abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
public String getDescription() {
return decoratedCoffee.getDescription();
}
public double getCost() {
return decoratedCoffee.getCost();
}
}
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription() + ", Milk";
}
@Override
public double getCost() {
return decoratedCoffee.getCost() + 0.5;
}
}
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription() + ", Sugar";
}
@Override
public double getCost() {
return decoratedCoffee.getCost() + 0.2;
}
}
class Coffee:
def get_description(self):
raise NotImplementedError("Method not implemented.")
def get_cost(self):
raise NotImplementedError("Method not implemented.")
class CoffeeDecorator:
def __init__(self, decorated_coffee):
self.decorated_coffee = decorated_coffee
def get_description(self):
return self.decorated_coffee.get_description()
def get_cost(self):
return self.decorated_coffee.get_cost()
class MilkDecorator(CoffeeDecorator):
def get_description(self):
return self.decorated_coffee.get_description() + ", Milk"
def get_cost(self):
return self.decorated_coffee.get_cost() + 0.5
class SugarDecorator(CoffeeDecorator):
def get_description(self):
return self.decorated_coffee.get_description() + ", Sugar"
def get_cost(self):
return self.decorated_coffee.get_cost() + 0.2
class Coffee {
getDescription() {
throw new Error('Method not implemented.');
}
getCost() {
throw new Error('Method not implemented.');
}
}
class CoffeeDecorator {
constructor(decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
getDescription() {
return this.decoratedCoffee.getDescription();
}
getCost() {
return this.decoratedCoffee.getCost();
}
}
class MilkDecorator extends CoffeeDecorator {
getDescription() {
return this.decoratedCoffee.getDescription() + ", Milk";
}
getCost() {
return this.decoratedCoffee.getCost() + 0.5;
}
}
class SugarDecorator extends CoffeeDecorator {
getDescription() {
return this.decoratedCoffee.getDescription() + ", Sugar";
}
getCost() {
return this.decoratedCoffee.getCost() + 0.2;
}
}
Complete Code of the above problem statement:
Below is the complete code of the above problem statement:
#include <iostream>
#include <string>
using namespace std;
class Coffee {
public:
virtual string getDescription() = 0;
virtual double getCost() = 0;
};
class PlainCoffee : public Coffee {
public:
string getDescription() override {
return "Plain Coffee";
}
double getCost() override {
return 2.0;
}
};
class CoffeeDecorator : public Coffee {
protected:
Coffee* decoratedCoffee;
public:
CoffeeDecorator(Coffee* decoratedCoffee) : decoratedCoffee(decoratedCoffee) {}
string getDescription() override {
return decoratedCoffee->getDescription();
}
double getCost() override {
return decoratedCoffee->getCost();
}
};
class MilkDecorator : public CoffeeDecorator {
public:
MilkDecorator(Coffee* decoratedCoffee) : CoffeeDecorator(decoratedCoffee) {}
string getDescription() override {
return decoratedCoffee->getDescription() + ", Milk";
}
double getCost() override {
return decoratedCoffee->getCost() + 0.5;
}
};
class SugarDecorator : public CoffeeDecorator {
public:
SugarDecorator(Coffee* decoratedCoffee) : CoffeeDecorator(decoratedCoffee) {}
string getDescription() override {
return decoratedCoffee->getDescription() + ", Sugar";
}
double getCost() override {
return decoratedCoffee->getCost() + 0.2;
}
};
int main() {
// Plain Coffee
Coffee* coffee = new PlainCoffee();
cout << "Description: " << coffee->getDescription() << endl;
cout << "Cost: $" << coffee->getCost() << endl;
// Coffee with Milk
Coffee* milkCoffee = new MilkDecorator(new PlainCoffee());
cout << "\nDescription: " << milkCoffee->getDescription() << endl;
cout << "Cost: $" << milkCoffee->getCost() << endl;
// Coffee with Sugar and Milk
Coffee* sugarMilkCoffee = new SugarDecorator(new MilkDecorator(new PlainCoffee()));
cout << "\nDescription: " << sugarMilkCoffee->getDescription() << endl;
cout << "Cost: $" << sugarMilkCoffee->getCost() << endl;
delete coffee;
delete milkCoffee;
delete sugarMilkCoffee;
return 0;
}
interface Coffee {
String getDescription();
double getCost();
}
class PlainCoffee implements Coffee {
@Override
public String getDescription() {
return "Plain Coffee";
}
@Override
public double getCost() {
return 2.0;
}
}
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription();
}
@Override
public double getCost() {
return decoratedCoffee.getCost();
}
}
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription() + ", Milk";
}
@Override
public double getCost() {
return decoratedCoffee.getCost() + 0.5;
}
}
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
@Override
public String getDescription() {
return decoratedCoffee.getDescription() + ", Sugar";
}
@Override
public double getCost() {
return decoratedCoffee.getCost() + 0.2;
}
}
public class Main {
public static void main(String[] args) {
// Plain Coffee
Coffee coffee = new PlainCoffee();
System.out.println("Description: " + coffee.getDescription());
System.out.println("Cost: $" + coffee.getCost());
// Coffee with Milk
Coffee milkCoffee = new MilkDecorator(new PlainCoffee());
System.out.println("\nDescription: " + milkCoffee.getDescription());
System.out.println("Cost: $" + milkCoffee.getCost());
// Coffee with Sugar and Milk
Coffee sugarMilkCoffee = new SugarDecorator(new MilkDecorator(new PlainCoffee()));
System.out.println("\nDescription: " + sugarMilkCoffee.getDescription());
System.out.println("Cost: $" + sugarMilkCoffee.getCost());
}
}
from abc import ABC, abstractmethod
class Coffee(ABC):
@abstractmethod
def get_description(self):
pass
@abstractmethod
def get_cost(self):
pass
class PlainCoffee(Coffee):
def get_description(self):
return "Plain Coffee"
def get_cost(self):
return 2.0
class CoffeeDecorator(Coffee):
def __init__(self, decorated_coffee):
self.decorated_coffee = decorated_coffee
def get_description(self):
return self.decorated_coffee.get_description()
def get_cost(self):
return self.decorated_coffee.get_cost()
class MilkDecorator(CoffeeDecorator):
def get_description(self):
return self.decorated_coffee.get_description() + ", Milk"
def get_cost(self):
return self.decorated_coffee.get_cost() + 0.5
class SugarDecorator(CoffeeDecorator):
def get_description(self):
return self.decorated_coffee.get_description() + ", Sugar"
def get_cost(self):
return self.decorated_coffee.get_cost() + 0.2
def main():
# Plain Coffee
coffee = PlainCoffee()
print(f"Description: {coffee.get_description()}")
print(f"Cost: ${coffee.get_cost()}")
# Coffee with Milk
milk_coffee = MilkDecorator(PlainCoffee())
print(f"\nDescription: {milk_coffee.get_description()}")
print(f"Cost: ${milk_coffee.get_cost()}")
# Coffee with Sugar and Milk
sugar_milk_coffee = SugarDecorator(MilkDecorator(PlainCoffee()))
print(f"\nDescription: {sugar_milk_coffee.get_description()}")
print(f"Cost: ${sugar_milk_coffee.get_cost()}")
if __name__ == "__main__":
main()
class Coffee {
getDescription() {
throw new Error('Method not implemented.');
}
getCost() {
throw new Error('Method not implemented.');
}
}
class PlainCoffee extends Coffee {
getDescription() {
return 'Plain Coffee';
}
getCost() {
return 2.0;
}
}
class CoffeeDecorator extends Coffee {
constructor(decoratedCoffee) {
super();
this.decoratedCoffee = decoratedCoffee;
}
getDescription() {
return this.decoratedCoffee.getDescription();
}
getCost() {
return this.decoratedCoffee.getCost();
}
}
class MilkDecorator extends CoffeeDecorator {
getDescription() {
return this.decoratedCoffee.getDescription() + ', Milk';
}
getCost() {
return this.decoratedCoffee.getCost() + 0.5;
}
}
class SugarDecorator extends CoffeeDecorator {
getDescription() {
return this.decoratedCoffee.getDescription() + ', Sugar';
}
getCost() {
return this.decoratedCoffee.getCost() + 0.2;
}
}
function main() {
// Plain Coffee
let coffee = new PlainCoffee();
console.log('Description: ' + coffee.getDescription());
console.log('Cost: $' + coffee.getCost());
// Coffee with Milk
let milkCoffee = new MilkDecorator(new PlainCoffee());
console.log('\nDescription: ' + milkCoffee.getDescription());
console.log('Cost: $' + milkCoffee.getCost());
// Coffee with Sugar and Milk
let sugarMilkCoffee = new SugarDecorator(new MilkDecorator(new PlainCoffee()));
console.log('\nDescription: ' + sugarMilkCoffee.getDescription());
console.log('Cost: $' + sugarMilkCoffee.getCost());
}
main();
Output
Description: Plain Coffee Cost: $ 2 Description: Plain Coffee, Milk Cost: $ 2.5 Description: Plain Coffee, Milk, Sugar Cost: $ 2.7