Sunday, November 10, 2013

Decorator design pattern

Hello

There is code example of Decorator design pattern. Decorator design pattern allows to add functionality or change behaviour  in run time, not like a static add functionality AKA inheritance.
My examples is pretty simple:
1. There is simple calculator, which knows how to perform 2 basic operations - adding and substrate numbers. Now I wish dynamically add functionality at run time. Here comes Decorator design pattern, which allows it.
2. Example from "Head First" book: there 2 basic coffee types: Brazilian and Arabica. But sometime i wish drink Arabica with double milk and sugar. Again, here comes Decorator design pattern, which allows it.
IMHO, there is no additional responsibilities, but it very close to Decorator.

Calculator 

Code:
namespace DecoratorDP
{
    public interface ISimpleCalculator
    {
        double Add(double a, double b);
        double Subs(double a, double b);
    }

    public class SimpleCalculator : ISimpleCalculator
    {
        public double Add(double a, double b)
        {
            return a + b;
        }

        public double Subs(double a, double b)
        {
            return a - b;
        }
    }

    public interface IAdvancedCalculator : ISimpleCalculator
    {
        double Mul(double a, double b);
        double Div(double a, double b);
    }

    public class AdvancedCalculator : IAdvancedCalculator
    {
        private ISimpleCalculator _simpleCalculator;

        public AdvancedCalculator(ISimpleCalculator simpleCalculator)
        {
            _simpleCalculator = simpleCalculator;
        }

        public double Mul(double a, double b)
        {
            return a * b;
        }

        public double Div(double a, double b)
        {
            return a / b;
        }

        public double Add(double a, double b)
        {
            return _simpleCalculator.Add(a, b);
        }

        public double Subs(double a, double b)
        {
            return _simpleCalculator.Subs(a, b);
        }
    }
}

Using:
ISimpleCalculator sc1 = new SimpleCalculator();
Assert.AreEqual(sc1.Add(5, 6), 11);
Assert.AreEqual(sc1.Subs(5, 6), -1);

IAdvancedCalculator ac = new AdvancedCalculator(sc1);
Assert.AreEqual(ac.Add(5, 6), 11);
Assert.AreEqual(ac.Subs(5, 6), -1);
Assert.AreEqual(ac.Mul(5, 6), 30);
Assert.AreEqual(ac.Div(66, 6), 11);

Class Diagram:

Coffee

Code:
using System;

namespace DecoratorDP
{
    public interface IBaseCofee
    {
        String GetName();
        double GetPrice();
    }

    public class ArabicaCofee : IBaseCofee
    {
        public string GetName() { return "Arabica coffee"; }
        public double GetPrice() { return 6.7; }
    }

    public class BrazilianCofee : IBaseCofee
    {
        public string GetName() { return "Brazilian coffee"; }
        public double GetPrice() { return 4.6; }
    }

    public interface IAdvancedCofee : IBaseCofee { }

    public class CofeeWithMilk : IAdvancedCofee
    {
        private IBaseCofee _coffee;

        public CofeeWithMilk(IBaseCofee coffee)
        {
            _coffee = coffee;
        }

        public string GetName()
        {
            return "Milk + " + _coffee.GetName();
        }

        public double GetPrice()
        {
            return 1.2 + _coffee.GetPrice();
        }
    }

    public class CofeeWithSugar : IAdvancedCofee
    {
        private IBaseCofee _coffee;

        public CofeeWithSugar(IBaseCofee coffee)
        {
            _coffee = coffee;
        }

        public string GetName()
        {
            return "Sugar + " + _coffee.GetName();
        }

        public double GetPrice()
        {
            return 0.3 + _coffee.GetPrice();
        }
    }
}

Using:
IBaseCofee baseArabica = new ArabicaCofee();
Assert.AreEqual(baseArabica.GetPrice(), 6.7);
Assert.AreEqual(baseArabica.GetName(), "Arabica coffee");

IBaseCofee baseBrazilian = new BrazilianCofee();
Assert.AreEqual(baseBrazilian.GetPrice(), 4.6);
Assert.AreEqual(baseBrazilian.GetName(), "Brazilian coffee");

IBaseCofee coffeeWithMilk = new CofeeWithMilk(baseArabica);
Assert.AreEqual(coffeeWithMilk.GetPrice(), 7.9);
Assert.AreEqual(coffeeWithMilk.GetName(), "Milk + Arabica coffee");

IBaseCofee coffeeWithDoubleMilk = new CofeeWithMilk(new CofeeWithMilk(baseArabica));
Assert.AreEqual(coffeeWithDoubleMilk.GetPrice(), 9.1);
Assert.AreEqual(coffeeWithDoubleMilk.GetName(), "Milk + Milk + Arabica coffee");

IBaseCofee coffeeWithDoubleMilkDoubleSugar = new CofeeWithSugar(new CofeeWithSugar(new CofeeWithMilk(new CofeeWithMilk(baseArabica))));
Assert.AreEqual(coffeeWithDoubleMilkDoubleSugar.GetPrice(), 9.7, 0.01);
Assert.AreEqual(coffeeWithDoubleMilkDoubleSugar.GetName(), "Sugar + Sugar + Milk + Milk + Arabica coffee");

Class Diagram:


that's it

No comments:

Post a Comment