๐ค What is the Decorator Pattern?
The Decorator Pattern is a structural design pattern that allows you to dynamically add new functionality to objects without changing their structure. It works by creating wrapper objects that encapsulate the original object and extend its behavior.
๐๏ธ Core Concepts of the Decorator Pattern
๐ Key Components
- Component: The base interface or abstract class
- ConcreteComponent: The basic implementation
- Decorator: The base decorator class
- ConcreteDecorator: Concrete decorator implementations
โ Advantages
- Dynamic extension of object functionality at runtime
- More flexible than inheritance for extending functionality
- Follows the Single Responsibility Principle
- Allows free combination of features
โ ๏ธ Disadvantages
- Can create many small objects
- Debugging can become complex
- Object identification can be difficult
๐ป Real-World Example Code
1. โ Java Example - Company System
// Component interface
interface Company {
String getDescription();
double getRevenue();
}
// ConcreteComponent
class BasicCompany implements Company {
private String name;
private double baseRevenue;
public BasicCompany(String name, double baseRevenue) {
this.name = name;
this.baseRevenue = baseRevenue;
}
@Override
public String getDescription() {
return name;
}
@Override
public double getRevenue() {
return baseRevenue;
}
}
// Decorator abstract class
abstract class CompanyDecorator implements Company {
protected Company company;
public CompanyDecorator(Company company) {
this.company = company;
}
@Override
public String getDescription() {
return company.getDescription();
}
@Override
public double getRevenue() {
return company.getRevenue();
}
}
// ConcreteDecorators
class TechDivision extends CompanyDecorator {
public TechDivision(Company company) {
super(company);
}
@Override
public String getDescription() {
return company.getDescription() + " + Tech Division";
}
@Override
public double getRevenue() {
return company.getRevenue() + 5000000;
}
}
class MarketingDivision extends CompanyDecorator {
public MarketingDivision(Company company) {
super(company);
}
@Override
public String getDescription() {
return company.getDescription() + " + Marketing Division";
}
@Override
public double getRevenue() {
return company.getRevenue() + 3000000;
}
}
class GlobalExpansion extends CompanyDecorator {
public GlobalExpansion(Company company) {
super(company);
}
@Override
public String getDescription() {
return company.getDescription() + " + Global Operations";
}
@Override
public double getRevenue() {
return company.getRevenue() * 1.5;
}
}
// Usage example
public class CompanyExample {
public static void main(String[] args) {
// Basic company
Company basicCompany = new BasicCompany("TechStart", 10000000);
System.out.println(basicCompany.getDescription() + " - Revenue: " + basicCompany.getRevenue());
// Add tech division
Company techCompany = new TechDivision(basicCompany);
System.out.println(techCompany.getDescription() + " - Revenue: " + techCompany.getRevenue());
// Add marketing division
Company fullCompany = new MarketingDivision(techCompany);
System.out.println(fullCompany.getDescription() + " - Revenue: " + fullCompany.getRevenue());
// Global expansion
Company globalCompany = new GlobalExpansion(fullCompany);
System.out.println(globalCompany.getDescription() + " - Revenue: " + globalCompany.getRevenue());
}
}
2. ๐ฆ TypeScript Example - Employee System
// Component interface
interface Employee {
getName(): string;
getSalary(): number;
getRole(): string;
}
// ConcreteComponent
class BasicEmployee implements Employee {
private name: string;
private baseSalary: number;
constructor(name: string, baseSalary: number) {
this.name = name;
this.baseSalary = baseSalary;
}
getName(): string {
return this.name;
}
getSalary(): number {
return this.baseSalary;
}
getRole(): string {
return "General Employee";
}
}
// Decorator abstract class
abstract class EmployeeDecorator implements Employee {
protected employee: Employee;
constructor(employee: Employee) {
this.employee = employee;
}
getName(): string {
return this.employee.getName();
}
getSalary(): number {
return this.employee.getSalary();
}
getRole(): string {
return this.employee.getRole();
}
}
// ConcreteDecorators
class TeamLeader extends EmployeeDecorator {
constructor(employee: Employee) {
super(employee);
}
getRole(): string {
return this.employee.getRole() + " + Team Leader";
}
getSalary(): number {
return this.employee.getSalary() + 500000;
}
}
class ProjectManager extends EmployeeDecorator {
constructor(employee: Employee) {
super(employee);
}
getRole(): string {
return this.employee.getRole() + " + Project Manager";
}
getSalary(): number {
return this.employee.getSalary() + 800000;
}
}
class SeniorDeveloper extends EmployeeDecorator {
constructor(employee: Employee) {
super(employee);
}
getRole(): string {
return this.employee.getRole() + " + Senior Developer";
}
getSalary(): number {
return this.employee.getSalary() + 1000000;
}
}
class Certification extends EmployeeDecorator {
private certName: string;
constructor(employee: Employee, certName: string) {
super(employee);
this.certName = certName;
}
getRole(): string {
return this.employee.getRole() + ` + ${this.certName} Certified`;
}
getSalary(): number {
return this.employee.getSalary() + 200000;
}
}
// Usage example
const basicEmployee = new BasicEmployee("John Developer", 4000000);
console.log(`${basicEmployee.getName()} - ${basicEmployee.getRole()} - Salary: ${basicEmployee.getSalary()}`);
const teamLeader = new TeamLeader(basicEmployee);
console.log(`${teamLeader.getName()} - ${teamLeader.getRole()} - Salary: ${teamLeader.getSalary()}`);
const seniorTeamLeader = new SeniorDeveloper(teamLeader);
console.log(`${seniorTeamLeader.getName()} - ${seniorTeamLeader.getRole()} - Salary: ${seniorTeamLeader.getSalary()}`);
const certifiedSeniorTeamLeader = new Certification(seniorTeamLeader, "AWS");
console.log(`${certifiedSeniorTeamLeader.getName()} - ${certifiedSeniorTeamLeader.getRole()} - Salary: ${certifiedSeniorTeamLeader.getSalary()}`);
const projectManagerRole = new ProjectManager(certifiedSeniorTeamLeader);
console.log(`${projectManagerRole.getName()} - ${projectManagerRole.getRole()} - Salary: ${projectManagerRole.getSalary()}`);
3. ๐ Python Example - Animal System
from abc import ABC, abstractmethod
# Component interface
class Animal(ABC):
@abstractmethod
def get_description(self) -> str:
pass
@abstractmethod
def get_abilities(self) -> list:
pass
@abstractmethod
def get_power_level(self) -> int:
pass
# ConcreteComponent
class BasicAnimal(Animal):
def __init__(self, name: str, species: str, base_power: int):
self.name = name
self.species = species
self.base_power = base_power
def get_description(self) -> str:
return f"{self.name} ({self.species})"
def get_abilities(self) -> list:
return ["Basic Survival"]
def get_power_level(self) -> int:
return self.base_power
# Decorator abstract class
class AnimalDecorator(Animal):
def __init__(self, animal: Animal):
self._animal = animal
def get_description(self) -> str:
return self._animal.get_description()
def get_abilities(self) -> list:
return self._animal.get_abilities()
def get_power_level(self) -> int:
return self._animal.get_power_level()
# ConcreteDecorators
class FlyingAbility(AnimalDecorator):
def get_description(self) -> str:
return self._animal.get_description() + " + Flying Ability"
def get_abilities(self) -> list:
abilities = self._animal.get_abilities().copy()
abilities.append("Flying")
return abilities
def get_power_level(self) -> int:
return self._animal.get_power_level() + 30
class SwimmingAbility(AnimalDecorator):
def get_description(self) -> str:
return self._animal.get_description() + " + Swimming Ability"
def get_abilities(self) -> list:
abilities = self._animal.get_abilities().copy()
abilities.append("Swimming")
return abilities
def get_power_level(self) -> int:
return self._animal.get_power_level() + 20
class PoisonousAbility(AnimalDecorator):
def get_description(self) -> str:
return self._animal.get_description() + " + Poisonous Ability"
def get_abilities(self) -> list:
abilities = self._animal.get_abilities().copy()
abilities.append("Poisonous Attack")
return abilities
def get_power_level(self) -> int:
return self._animal.get_power_level() + 50
class CamouflageAbility(AnimalDecorator):
def get_description(self) -> str:
return self._animal.get_description() + " + Camouflage Ability"
def get_abilities(self) -> list:
abilities = self._animal.get_abilities().copy()
abilities.append("Camouflage")
return abilities
def get_power_level(self) -> int:
return self._animal.get_power_level() + 25
class SuperStrength(AnimalDecorator):
def get_description(self) -> str:
return self._animal.get_description() + " + Super Strength"
def get_abilities(self) -> list:
abilities = self._animal.get_abilities().copy()
abilities.append("Super Strength")
return abilities
def get_power_level(self) -> int:
return self._animal.get_power_level() * 2
# Usage example
def print_animal_info(animal: Animal):
print(f"๐ฆ {animal.get_description()}")
print(f"๐ช Abilities: {', '.join(animal.get_abilities())}")
print(f"โก Power Level: {animal.get_power_level()}")
print("-" * 50)
# Basic animals
tiger = BasicAnimal("Tiger", "Predator", 80)
print_animal_info(tiger)
eagle = BasicAnimal("Eagle", "Bird of Prey", 60)
print_animal_info(eagle)
snake = BasicAnimal("Snake", "Reptile", 40)
print_animal_info(snake)
# Enhanced abilities
flying_tiger = FlyingAbility(tiger)
print_animal_info(flying_tiger)
swimming_flying_tiger = SwimmingAbility(flying_tiger)
print_animal_info(swimming_flying_tiger)
super_swimming_flying_tiger = SuperStrength(swimming_flying_tiger)
print_animal_info(super_swimming_flying_tiger)
# Enhanced eagle
camouflage_eagle = CamouflageAbility(eagle)
super_camouflage_eagle = SuperStrength(camouflage_eagle)
print_animal_info(super_camouflage_eagle)
# Enhanced snake
poisonous_snake = PoisonousAbility(snake)
camouflage_poisonous_snake = CamouflageAbility(poisonous_snake)
swimming_camouflage_poisonous_snake = SwimmingAbility(camouflage_poisonous_snake)
print_animal_info(swimming_camouflage_poisonous_snake)
๐ Real-World Use Cases
๐ฑ UI Component Systems
- Dynamically add icons, loading spinners, tooltips to basic buttons
- Each feature can be combined independently
๐ Middleware Systems
- Add authentication, logging, caching, compression to HTTP requests in layers
- Express.js and Spring Boot middleware chains
๐พ Data Stream Processing
- Add encryption, compression, buffering to basic data streams
- Java's InputStream/OutputStream classes
๐ฎ Game Development
- Dynamically equip characters with weapons, armor, skills, buffs
- Item combination systems
๐ค Comparison with Other Patterns
๐ Decorator vs Inheritance
- Inheritance: Fixed at compile time, single extension only
- Decorator: Dynamic at runtime, multiple feature combinations
๐ง Decorator vs Adapter
- Adapter: Connects incompatible interfaces
- Decorator: Adds functionality to the same interface
๐๏ธ Decorator vs Composite
- Composite: Represents tree structure object relationships
- Decorator: Linear feature extension
๐ Best Practices
โจ Effective Usage
- Single Responsibility Principle: Each decorator handles one feature
- Interface Consistency: All decorators implement the same interface
- Order Independence: Decorator application order shouldn't affect results
- Performance Consideration: Too many decorator chains can impact performance
๐ซ Things to Avoid
- Debugging difficulties from complex decorator chains
- Strong dependencies between decorators
- Breaking interface consistency
๐ฏ Conclusion
The Decorator Pattern is a powerful design pattern that allows flexible extension of object functionality. It overcomes the limitations of inheritance and enables dynamic feature combination at runtime, making it extremely useful in modern software development. It's widely used in microservice architectures, middleware systems, and UI component libraries.
The key is understanding the concept of "extension through feature combination" and implementing it appropriately for each language's characteristics. Use the examples above as a reference to apply the Decorator Pattern in your projects! ๐
Tags: DecoratorPattern, DesignPattern, StructuralPattern, Java, TypeScript, Python, ObjectOriented, SoftwareArchitecture, ProgrammingPattern, Developer
๋๊ธ