A Simple implementation of the Decorator Design Pattern using C#

The main motivation before the decorator pattern is to be able to add data and behavior to objects dynamically
without relying on inheritance.

A decorator usually conforms to the interface of the component its decorating.
Lets see this with an example.

Am building a system that calculates the price of a pizza. I can have many toppings and the total price of
the pizza is calculated based on what toppings I pick. One way to do this would be to use inheritance and
class hierarchies like Pizza, CheesePizza, ChickenPizza etc…which can get very inflexible.

A better way is to implement this using decorators. Below PizzaWithCheese decorates
the Pizza and adds the price of cheese to the total and so does the PizzaWithChicken.
When executed you should see the following output:

Total for cheese pizza: 15
Total for chicken pizza: 16
Total for cheese + chicken pizza: 21

class DecoratorPattern

{

    private interface IPizza

    {

        int GetPrice();

    }

    private class Pizza : IPizza

    {

        public int GetPrice()

        {

            return 10;

        }

    }

    //Decorator 1

    private class PizzaWithCheese : IPizza

    {

        private IPizza \_pizza;

        private int \_priceofCheese;

        public PizzaWithCheese(IPizza pizza, int priceofCheese)

        {

            \_pizza = pizza;

            \_priceofCheese = priceofCheese;

        }

        public int GetPrice()

        {

            //get price of the base pizza and add price of cheese to it

            return \_pizza.GetPrice() + \_priceofCheese;

        }

    }

    //Decorator 2

    private class PizzaWithChicken : IPizza

    {

        private IPizza \_pizza;

        private int \_priceofChicken;

        public PizzaWithChicken(IPizza pizza, int priceofChicken)

        {

            \_pizza = pizza;

            \_priceofChicken = priceofChicken;

        }

        public int GetPrice()

        {

            //get price of the base pizza and add price of chicken to it

            return \_pizza.GetPrice() + \_priceofChicken;

        }

    }

    public static void Test()

    {           

        var pizzaWithCheese = new PizzaWithCheese(new Pizza(), 5);

        var pizzaWithChicken = new PizzaWithChicken(new Pizza(), 6);

        //pizza with chicken and cheese is easy to build now.

        //we can keep decotaring the base pizza with as many decorators as necessary at runtime

        var pizzaWithChickenAndCheese = new PizzaWithChicken(pizzaWithCheese, 6);

        Console.WriteLine("Total for cheese pizza: " + pizzaWithCheese.GetPrice());

        Console.WriteLine("Total for chicken pizza: " + pizzaWithChicken.GetPrice());

        Console.WriteLine("Total for cheese + chicken pizza: " + pizzaWithChickenAndCheese.GetPrice());

    }

}
This article is part of the GWB Archives. Original Author: Asif Maniar

New on Geeks with Blogs

  • We Won The One Award I Actually Care About

    Full Scale made the Inc. 5000 for the fifth year straight, the 12th listing across my three companies. Here is why the one award you cannot buy is worth stopping for.

  • Your Customers Build the Features Now

    I let a tool I liked sit dead for a year rather than build the features I wanted. An MCP server meant I never had to, and your customers can do the same to your product.

  • Get the Size of a Directory in Linux the Easy Way

    du -sh for the quick answer, ncdu for the cleanup, df for the disk itself: every command for checking directory size in Linux, plus why du and df never agree.

  • Vim Search and Replace: The Ultimate Guide

    One :%s command replaces every match in a file before a find dialog would even open. The Vim substitute patterns worth the muscle memory: flags, ranges, capture groups, and multi-file edits.