Design patterns (4 Part Series)
- Design patterns: Singleton
- Design patterns: Factory
- Design patterns: Observer
- Design patterns: Decorator
Hey there, my last posts looked at creational and behavioral design patterns. This time we’re going to be going over our first structural pattern, the decorator pattern.
Structural patterns give us a way of combining objects into larger structures while keeping these structures flexible and efficient. When you think of the decorator pattern, think of Matryoshka dolls (the dolls that stack inside of one another). You’ll soon see that the decorator pattern gives our code flexibility at run-time while extending class functionality.
If you don’t know what a wrapper class is, you might want to check out this post first! (But it’s not required)
The decorator pattern allows us to add functionality to our classes without directly modifying or inheriting from them. We’re able to add behavior to our classes by wrapping them up inside other classes.
We can dynamically add responsibilities to objects with a component and decorator relationship. The decorator conforms to the component’s interface while also having a component object within itself. The decorator object is then effectively able to add functionality to the component by adding functionality to itself.
Using C#, the pattern looks like this:
using System;using System.Collections.Generic;public class Program{public static void Main(){ConcreteComponent component = new ConcreteComponent();component.DoSomething();ConcreteDecorator decorator = new ConcreteDecorator(new ConcreteComponent());decorator.DoSomethingElse();}// 2. The concrete component (what we're decorating)class ConcreteComponent : IComponent{public void DoSomething(){Console.WriteLine("Doing something!");}}// 1. The component's interfaceinterface IComponent{void DoSomething();}// 3. The decoratorabstract class Decorator : IComponent{protected IComponent Component { get; set; }public Decorator(IComponent component){this.Component = component;}public void DoSomething(){this.Component.DoSomething();}}// 4. The concrete decoratorclass ConcreteDecorator : Decorator{public ConcreteDecorator(IComponent component) : base(component) {}public void DoSomethingElse(){Console.WriteLine("Doing something else!");}}}
Let’s write a program that adds functionality to a Calculator
class. Our Calculator
class only has an Add
method right now, but we want to add a Subtract
method so we’ll create a decorator for the class.
using System;public class Program{public static void Main(){Calculator calculator = new Calculator();Console.WriteLine("Regular Calculator:");Console.WriteLine(calculator.Add(4, 3) + "\n");BetterCalculator betterCalculator = new BetterCalculator(calculator);Console.WriteLine("Decorated Calculator:");Console.WriteLine(betterCalculator.Add(4, 3));Console.WriteLine("But I can also subtract!");Console.WriteLine(betterCalculator.Subtract(4, 3));}class Calculator : ICalculator{public override int Add(int x, int y){return x + y;}}abstract class ICalculator{public abstract int Add(int x, int y);}class Decorator : ICalculator{ICalculator myCalc { get; set; }public Decorator(ICalculator calculator){this.myCalc = calculator;}public override int Add(int x, int y){return this.myCalc.Add(x, y);}}class BetterCalculator : Decorator{public BetterCalculator(ICalculator calc) : base(calc) {}public int Subtract(int x, int y){return x - y;}}}
Disclaimer: There are a lot of resources for learning design patterns, and they can be implemented in different ways. I would recommend exploring more resources when finished with this post.
Free Resources