1. Definition
The Decorator Design Pattern lets you add further responsibilities to an object dynamically, without modifying its structure. Decorators provide a flexible alternative to subclassing for extending functionality.
2. Problem Statement
Sometimes we need to add responsibilities to individual objects, not to an entire class. A straightforward way might be to extend the class, but it can become cumbersome and lead to a large number of subclasses which can be hard to maintain.
3. Solution
The Decorator Pattern suggests creating a set of decorator classes that mirror the type of the objects they will augment. You can use these to wrap concrete components with new behaviors.
4. Real-World Use Cases
1. Adding window dressing or borders to graphical windows.
2. Adding responsibilities to UI components dynamically, like scroll bars.
3. Enhancing classes in third-party libraries without altering the original code.
5. Implementation Steps
1. Ensure there's a common interface between your primary object and the decorators.
2. Create concrete implementations of the primary object.
3. For each additional behavior, create a new decorator class mirroring the primary object's interface.
4. Decorators wrap around the primary or other decorator objects, adding their own behavior when methods are invoked.
6. Implementation in Ruby
# Step 1: Common Interface
module Beverage
def cost
raise NotImplementedError, 'Subclasses must define `cost`.'
end
end
# Step 2: Concrete Implementations
class Coffee
include Beverage
def cost
5
end
end
# Step 3: Decorator Classes
class SugarDecorator
include Beverage
def initialize(beverage)
@beverage = beverage
end
def cost
@beverage.cost + 1
end
end
class MilkDecorator
include Beverage
def initialize(beverage)
@beverage = beverage
end
def cost
@beverage.cost + 2
end
end
# Step 4: Client Code
coffee = Coffee.new
sugar_coffee = SugarDecorator.new(coffee)
double_sugar_milk_coffee = MilkDecorator.new(SugarDecorator.new(sugar_coffee))
puts double_sugar_milk_coffee.cost
Output:
8
Explanation:
1. Beverage is the common interface for both the primary object and the decorators.
2. Coffee is a concrete implementation of the Beverage interface.
3. SugarDecorator and MilkDecorator are the decorator classes. They wrap around a Beverage object, adding or altering behaviors.
4. The client code demonstrates how to decorate a Coffee object with additional behaviors using decorators. Each decorator wraps the previously decorated object.
7. When to use?
Use the Decorator Design Pattern when:
1. You need to add responsibilities to individual objects dynamically and transparently, without affecting other objects.
2. Extending the responsibilities of a class through inheritance isn't feasible due to its inflexibility.
3. You want to keep new responsibilities separate by using individual classes for each feature.
Comments
Post a Comment