Introducing the Decorator design pattern

Introducing the Decorator design pattern

Read Time : 3 Minutes

Wednesday, 26 April 2023

Design patterns are proven solutions to software design problems. They help improve code quality, promote reusability, and increase maintainability. We use them to save time and produce quality, extensible and flexible code. In this article, we are going to introduce the Decorator design pattern.

The Decorator design pattern is a structural design pattern that allows you to dynamically add behavior to an object at runtime. This template can add additional behavior to a class or modify existing behavior without changing the parent object.

There are several key elements in the Decorator pattern:

  • Component: is an interface or abstract class that defines common methods for Concrete Component and Decorator.
  • Concrete Component: A class that implements the Component interface and provides the basic functionality of an object that can be modified.
  • Decorator: An abstract class that implements the Component interface and holds a reference to the Component object. Decorator adds extra behavior to the object by calling the main object's methods and adding some extra processing before or after the method.
  • Concrete Decorator: It is a class that implements Decorator and adds new features to the object.
decorator

The Decorator pattern allows you to add functionality to an object without changing its structure. This feature can be useful when you need to add functionality to an object that is used in different parts of your code, and you don't want to change all the places where that object is used.

Here is a simple example of the Decorator pattern in C#:

// Component interface
public interface IPizza
{
    string GetDescription();
    double GetCost();
}
// Concrete Component class
public class PlainPizza : IPizza
{
    public string GetDescription()
    {
        return "Thin dough";
    }
    public double GetCost()
    {
        return 4.00;
    }
}
// Decorator abstract class
public abstract class ToppingDecorator : IPizza
{
    protected IPizza _pizza;
    public ToppingDecorator(IPizza pizza)
    {
        _pizza = pizza;
    }
    public virtual string GetDescription()
    {
        return _pizza.GetDescription();
    }
    public virtual double GetCost()
    {
        return _pizza.GetCost();
    }
}
// Concrete Decorator classes
public class TomatoSauce : ToppingDecorator
{
    public TomatoSauce(IPizza pizza) : base(pizza) { }
    public override string GetDescription()
    {
        return _pizza.GetDescription() + ", tomato sauce";
    }
    public override double GetCost()
    {
        return _pizza.GetCost() + 0.35;
    }
}
public class Mozzarella : ToppingDecorator
{
    public Mozzarella(IPizza pizza) : base(pizza) { }
    public override string GetDescription()
    {
        return _pizza.GetDescription() + ", mozzarella";
    }
    public override double GetCost()
    {
        return _pizza.GetCost() + 0.50;
    }
}
// Client code
class Program
{
    static void Main(string[] args)
    {
        // Create a plain pizza
        IPizza basicPizza = new PlainPizza();
        // Add tomato sauce and mozzarella
        IPizza pizzaWithSauceAndCheese = new TomatoSauce(new Mozzarella(basicPizza));
        Console.WriteLine($"Description: {pizzaWithSauceAndCheese.GetDescription()}");
       Console.WriteLine($"Cost: {pizzaWithSauceAndCheese.GetCost():C}");
    }
}

In this example, we have the IPizza interface that defines the GetDescription and GetCost methods. We also have the PlainPizza class that implements the IPizza interface.

The ToppingDecorator abstract class implements the IPizza interface and maintains an object of type IPizza. Concrete Decorator classes such as TomatoSauce and Mozzarella implement the ToppingDecorator class and add their own behavior.

Finally, in the client code, we create a PlainPizza instance and modify it with TomatoSauce and Mozzarella.

To read about other design patterns, you can use the list below. There is also a code repository on GitHub that includes all the design patterns.

design patterns

Creational:Factory Design Pattern
Builder Design Pattern
Singleton Design Pattern
Prototype Design Pattern
Abstract Factory Design Pattern
Structural:Adapter Design Pattern
Bridge Design Pattern
Composite Design Pattern
Decorator Design Pattern
Facade Design Pattern
Flyweight Design Pattern
Proxy Design Pattern
Behavioral:Chain of Responsibility Design Pattern
Command Design Pattern
Interpreter Design Pattern
Mediator Design Pattern
Memento Design Pattern
Observer Design Pattern
State Design Pattern
Strategy Design Pattern
Template Method Design Pattern
Visitor Design Pattern
Iterator Design Pattern
  • Share:
reza babakhani
Reza Babakhani

I am Reza Babakhani, a software developer. Here I write my experiences, opinions and suggestions about technology. I hope that what I write is useful for you.

Latest post

Service Mesh Simplifying Microservice Communication

In the ever-evolving landscape of software development, microservices architecture has gained considerable popularity due to its scalability, flexibility, and extensibility. However, as the number of microservices in an application increases, it becomes increasingly challenging to manage their communication and ensure that they are all properly visible. This is where Service Mesh comes into play.

The Importance of Edge Computing

Due to the speed of technological evolution, one of the concepts that has attracted a lot of attention and changes the way we interact with digital systems is edge computing.

What is event-driven architecture?

Event-driven architecture (EDA) is a software design pattern that has become increasingly popular in modern software development. In this architecture, the flow of data is determined by the occurrence of events. Unlike traditional centralized systems that are constantly checking for new status. Event-driven architecture is especially useful for systems that need to process large amounts of data in real-time.

leave a comment