1 of 8

Decorator Design Pattern �(Structural)

Thanh Le – Software Architect / Technical Consultant

Complexity: 2/3

Popularity: 2/3

2 of 8

Intent

  • Decorator is a structural design pattern that lets you add new functionality to an existing object without changing its structure.
  • It works by wrapping the original class under a decorator class without modifying the original class, and add new behaviors/operators at runtime.

Image source: internet

3 of 8

Motivation

Imagine that you’re working on a notification library which lets other programs notify their users about important events.

The initial version of the library was based on the Notifier class that had only a few fields, a constructor and a single send method. The method could accept a message argument from a client and send the message to a list of emails that were passed to the notifier via its constructor. ����

Image source: internet

A program could use the notifier class to send notifications about important events to a predefined set of emails.

4 of 8

Motivation (cont)

One day, users expect more than just email notifications. Many of them would like to receive an SMS about critical issues. Others would like to be notified on Facebook and, of course, the corporate users would love to get Slack notifications.

Besides, they also want to send several notification types at once.

What should we do?

Image source: internet

Each notification type is implemented as a notifier’s subclass.

5 of 8

Solution

  • You can apply decorator design pattern.
  • Leave the simple email notification behavior inside the base Notifier class, and turn all other notification methods into decorators.
  • The client code would need to wrap a basic notifier object into a set of decorators that match the client’s preferences. The resulting objects will be structured as a stack.
  • The last decorator in the stack would be the object that the client actually works with.�

Image source: internet

Various notification methods become decorators.

6 of 8

Structure

Image source: internet

  • The Component declares the common interface for both wrappers and wrapped objects.

  • Concrete Component is a class of objects being wrapped. It defines the basic behavior, which can be altered by decorators.

  • The Base Decorator class has a field for referencing a wrapped object. The field’s type should be declared as the component interface so it can contain both concrete components and decorators. The base decorator delegates all operations to the wrapped object.

  • Concrete Decorators define extra behaviors that can be added to components dynamically. Concrete decorators override methods of the base decorator and execute their behavior either before or after calling the parent method.

  • The Client can wrap components in multiple layers of decorators, as long as it works with all objects via the component interface.

��

7 of 8

Pros/Cons

  • Open-Closed Principle: You can add new behavior to an object without changing its original implementation, thus keeping the codebase stable and reducing the risk of introducing bugs.
  • Dynamic behavior addition: Decorators allow you to dynamically add new behavior to an object at runtime. You can add or remove decorators as needed, giving you fine-grained control over the behavior of an object.
  • Single Responsibility Principle: Each decorator class adds a specific behavior or responsibility, and the combination of decorators allows for the stacking of multiple responsibilities without bloating the core object.

  • Complexity: With multiple layers of decorators, it can become challenging to understand the flow of control and track the behavior modifications.
  • The use of decorators can also result in a large number of small classes, which may increase code size and make the overall structure more intricate.

8 of 8

Practice

https://github.com/thanhle0212/23GoF-Design-Patterns-CSharp