Early previewThis guide is in development. Items tagged verify are still being checked against official docs.
nebx Learn
GitHub
Menu
C#

C#

A productive, strongly typed language for the whole .NET platform.

Paradigm
OOP, functional features
Typing
Static, strong, nullable-aware
Memory
Generational GC
Runs
.NET runtime (JIT) or Native AOT
Concurrency
Tasks, async/await, channels
Structural pattern

Decorator

Intent

Attaches new behaviours to objects by placing them inside wrapper objects that share the same interface.

Problem

Users want notifications by email, SMS and Slack in any combination. Subclassing every combination explodes.

Solution

Wrap the base notifier in decorators. Each adds its behaviour and delegates to the wrapped object.

Real-world analogy

Think of it like this

Dressing in layers: a sweater when it's cold, a jacket over it, a raincoat on top when it rains. Each layer adds something and can come off.

Structure

association / extends implements / depends on
Client 5 «interface» Component + execute() 1 ConcreteComponent + execute() 2 BaseDecorator - wrappee: Component+ execute() 3 ConcreteDecorator + execute()+ extra() 4

Hover or tap a numbered role to highlight it in the diagram.

  1. 1Component — Component declares the interface shared by wrappers and wrapped objects.
  2. 2ConcreteComponent — Concrete Component is the object being wrapped; it defines the basic behaviour.
  3. 3BaseDecorator — Base Decorator holds a reference to a wrapped Component and delegates all work to it.
  4. 4ConcreteDecorator — Concrete Decorators add behaviour before or after calling the parent method.
  5. 5Client — Client wraps components in as many layers as it needs.

Try it

InteractiveWrap the notifier in layers, then send. Calls travel in, output comes back out.
Wrap with (in click order)

    
// output appears here

Code example

decorator.cs
public interface INotifier { void Send(string message); }

public class EmailNotifier : INotifier
{
    public void Send(string message) => Console.WriteLine(
quot;email: {message}"); } public abstract class NotifierDecorator : INotifier { private readonly INotifier inner; protected NotifierDecorator(INotifier inner) => this.inner = inner; public virtual void Send(string message) => inner.Send(message); } public class SlackDecorator : NotifierDecorator { public SlackDecorator(INotifier inner) : base(inner) { } public override void Send(string message) { base.Send(message); Console.WriteLine(
quot;slack: {message}"); } } // INotifier n = new SlackDecorator(new EmailNotifier());

Applicability

Use Decorator when adding behaviour at runtime without changing the object's code.

Use Decorator when inheritance is awkward or impossible (final classes).

How to implement

  1. Make sure the domain can be a primary component with optional layers
  2. Define a component interface
  3. Create a concrete component
  4. Create a base decorator holding a wrapped component and delegating to it
  5. Create concrete decorators that add behaviour before or after delegating
  6. Let the client compose decorators

Pros and cons

Pros

  • Extend behaviour without subclassing
  • Combine behaviours by stacking wrappers
  • Single Responsibility per wrapper

Cons

  • Hard to remove a specific wrapper from the stack
  • Order of wrappers matters
  • Many small objects can be hard to debug

Check yourself

Check yourself

Add compression and then encryption around a file stream, in any combination, at runtime.

Saved in this browser only. Part of Structural patterns (0/7), Hands-on: patterns with live demos (0/5).