The Decorator Pattern is a structural design pattern that allows behavior to be added to individual objects, either statically or dynamically, without affecting the behavior of other objects from the same class. This pattern is particularly useful in scenarios where subclassing would lead to an explosion of classes due to the need for various combinations of behaviors.
The Decorator Pattern works by wrapping a concrete component with a decorator that adds new functionality. This allows for flexible and reusable code. Here’s a simple example in Python:
class Coffee:
def cost(self):
return 5
class MilkDecorator:
def __init__(self, coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost() + 1
class SugarDecorator:
def __init__(self, coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost() + 0.5
# Usage
coffee = Coffee()
print(f"Cost of coffee: ${coffee.cost()}") # Output: Cost of coffee: $5
milk_coffee = MilkDecorator(coffee)
print(f"Cost of milk coffee: ${milk_coffee.cost()}") # Output: Cost of milk coffee: $6
sugar_milk_coffee = SugarDecorator(milk_coffee)
print(f"Cost of sugar milk coffee: ${sugar_milk_coffee.cost()}") # Output: Cost of sugar milk coffee: $6.5
In this example, we have a Coffee class that represents a basic coffee. The MilkDecorator and SugarDecorator classes add additional costs to the coffee without modifying the original Coffee class. This demonstrates how decorators can enhance functionality dynamically.
The Decorator Pattern is a powerful tool in object-oriented design that allows developers to extend the functionality of objects without the need for extensive subclassing. By understanding and applying this pattern, software engineers and data scientists can create more flexible and maintainable code, which is essential for technical interviews and real-world applications.