VOOZH about

URL: https://www.geeksforgeeks.org/system-design/decorator-pattern/

⇱ Decorator Design Pattern - GeeksforGeeks


  • Courses
  • Tutorials
  • Interview Prep

Decorator Design Pattern

Last Updated : 6 May, 2026

The 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.

  • Wraps existing objects using decorator classes to add new behavior at runtime.
  • Extends functionality without modifying original code, following the open/closed principle.
👁 Decorator-Design-Pattern
Decorator Design Pattern

In the above Diagram

  • This represents Pizza as the base component.
  • Capsicum acts as the first decorator, wrapping the pizza and adding its own cost using getCost().
  • Cheese Burst is another decorator that wraps the previous layer and adds additional cost.
  • The final price is calculated as Pizza + Capsicum + Cheese Burst, demonstrating how the Decorator Pattern adds behavior dynamically.

Real-World Examples

The Decorator Pattern is widely used in software systems to dynamically add new features or behaviors to objects without modifying their original structure.

1. Coffee Shop Application: A basic coffee object is enhanced with add-ons like milk, sugar, or whipped cream. Each add-on acts as a decorator that dynamically adds cost and behavior.

2. Video Streaming Platforms: Videos can be wrapped with decorators for subtitles, audio enhancements, or language options. Multiple features can be added without modifying the original video object.

3. Text Processing Applications: Plain text can be decorated with bold, italic, or underline formatting. Multiple text styles can be combined dynamically using decorators.

4. Video Streaming Platforms: A video object can be enhanced with features like subtitles, language options, or audio enhancements. These features act as decorators, adding functionality without modifying the original video.

5. Java I/O Streams: In Java, a FileInputStream can be wrapped with BufferedInputStream or DataInputStream. Each wrapper adds new functionality without altering the core stream.

Components

The Decorator Pattern consists of key elements that work together to dynamically extend object behavior.

  • Component Interface: Defines common operations for components and decorators.
  • Concrete Component: Core object with basic functionality.
  • Decorator: Abstract wrapper that holds a Component reference and adds behavior.
  • Concrete Decorator: Specific decorators that extend functionality of the component.

Working

The Decorator Pattern works by wrapping objects to add new behavior without modifying their original structure.

  1. Define a component interface that both the core object and decorators implement.
  2. Create a concrete component that implements the interface.
  3. Create decorator classes that also implement the interface and have a reference to a component object.
  4. Decorator classes add or override behavior by delegating to the wrapped object.

Uses

The Decorator Pattern is used when:

  • We want to add responsibilities to objects without subclassing, avoiding the need to create multiple derived classes.
  • We need to combine behaviors flexibly at runtime, allowing features to be added or removed dynamically as needed.
  • We want to extend functionality of a class in a transparent way, without modifying its original code or structure.

Implementation Example

Problem statement

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.

👁 class_diagram_of_decorator_design_pattern
class diagram

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.

This example shows the practical application of the design pattern using 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.

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.

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.

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.

Complete Code of above example:


Output
Description: Plain Coffee
Cost: $2

Description: Plain Coffee, Milk
Cost: $2.5

Description: Plain Coffee, Milk, Sugar
Cost: $2.7

Advantages

This pattern is useful when you want to add responsibilities to objects dynamically at runtime.

  • Improves flexibility by allowing behavior to be added or removed at runtime.
  • Promotes Single Responsibility Principle, as functionality can be divided among classes.
  • Avoids the use of large subclasses that combine multiple behaviors.

Disadvantages

While powerful, this pattern has some downsides:

  • Can make the system more complex due to many small decorator classes.
  • Debugging and understanding the flow of decorated objects may be harder.
  • Overuse can lead to code that is difficult to maintain.
Comment
Article Tags:

Explore