Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

Decorator Pattern

What it is

The Decorator pattern wraps an object in successive layers, each adding behavior before or after delegating to the wrapped object. All layers share the same interface, so the caller treats the chain identically to the original object.

Structure

Handler (interface)
    └── BaseHandler          — core logic
    └── AuthDecorator        — wraps a Handler, checks auth
    └── LoggingDecorator     — wraps a Handler, logs request/response
    └── MetricDecorator      — wraps a Handler, records metrics

Each decorator holds a wrappedHandler Handler field and calls it inside its own Handle() implementation.

How this example works

var handler decorator.Handler = decorator.NewBaseHandler()
handler = decorator.NewAuthDecorator(handler)
handler = decorator.NewLoggingDecorator(handler)
handler = decorator.NewMetricDecorator(handler)

handler.Handle(decorator.Request{})

Calling handler.Handle() on the outermost decorator triggers a chain:

MetricDecorator.Handle()
  └── LoggingDecorator.Handle()
        └── AuthDecorator.Handle()
              └── BaseHandler.Handle()

Each decorator runs its own pre/post logic around the inner call.

Key rules

  • Every decorator must implement the same interface as the object it wraps.
  • Decorators are composed at runtime, not compile time — the order matters.
  • Adding or removing a cross-cutting concern requires no changes to other layers.

When to use

  • You need to add responsibilities to objects without subclassing.
  • Cross-cutting concerns (auth, logging, metrics, caching) should be applied independently and in combination.
  • The number of feature combinations would make inheritance impractical.