Design patterns in C# – part 1 (Decorator pattern)

Role

Providing a way of attaching new state and behavior to an object dynamically.

Design

Image of UML Diagram of Decorator Patern

Implementation

  • IComponent -> IDragon
  • Client ->TestDecoratorPattern
  • Component -> Dragon
  • Decorator -> FireBlechingDragon, IceDragon, MagicDragon
namespace DecoratorPattern
{
    public interface IDragon
    {
        int Strength { get; }
        int Speed { get; }
        string Attack();
    }
}
namespace DecoratorPattern
{
    public class Dragon : IDragon
    {
        public Dragon()
        {
            this.Strength = 3;
            this.Speed = 3;
        }

        public int Strength { get; private set; }

        public int Speed { get; private set; }

        public string Attack()
        {
            return "Bite";
        }
    }
}
using System;

namespace DecoratorPattern
{
    public class FireBlechingDragon : IDragon
    {
        private readonly IDragon _dragon;

        public FireBlechingDragon(IDragon dragon)
        {
            this._dragon = dragon;
            this.Speed = dragon.Speed + 2;
            this.Strength = dragon.Strength + 5;
        }

        public int Strength { get; private set; }

        public int Speed { get; private set; }

        public string Attack()
        {
            return String.Concat(this._dragon.Attack(), " and Fire Ball");
        }
    }
}
using System;

namespace DecoratorPattern
{
    public class IceDragon : IDragon
    {
        private readonly IDragon _dragon;

        public IceDragon(IDragon dragon)
        {
            this._dragon = dragon;
            this.Speed = dragon.Speed + 5;
            this.Strength = dragon.Strength + 2;
        }

        #region IDragon Members

        public int Strength { get; private set; }

        public int Speed { get; private set; }

        public string Attack()
        {
            return String.Concat(this._dragon.Attack(), " and Ice Ball");
        }

        #endregion
    }
}
namespace DecoratorPattern
{
    public class MagicDragon : IDragon
    {
        private readonly IDragon _dragon;

        public MagicDragon(IDragon dragon)
        {
            this._dragon = dragon;
            this.Strength = dragon.Strength + 1;
            this.Speed = dragon.Speed + 1;
        }

        #region IDragon Members

        public int Strength { get; private set; }

        public int Speed { get; private set; }

        public string Attack()
        {
            return this._dragon.Attack();
        }

        #endregion

        public string Magic()
        {
            return "Magic lightning";
        }
    }
}
using System;

namespace DecoratorPattern
{
    public class TestDecoratorPattern
    {
        public static void Display(string name, IDragon dragon)
        {
            Console.WriteLine(String.Format("{0} \nStrength: {1}, Speed: {2}\nAttack: {3}", name, dragon.Strength, dragon.Speed, dragon.Attack()));
        }

        public static void Main()
        {
            IDragon dragon = new Dragon();
            IDragon fireDragon = new FireBlechingDragon(dragon);
            IDragon iceDragon = new IceDragon(dragon);
            IDragon magicDragon = new MagicDragon(dragon);
            IDragon magicIceDragon = new MagicDragon(iceDragon);

            Display("Common dragon: ", dragon);
            Display("Fire-bleching dragon: ", fireDragon);
            Display("Ice dragon: ", iceDragon);
            Display("Magic dragon: ", magicDragon);
            Display("Magic ice dragon: ", magicIceDragon);

            Console.WriteLine("Magic attack from magic dragon: {0}", ((MagicDragon) magicDragon).Magic());
        }
    }
}

OUTPUT:

Common dragon:
Strength: 3, Speed: 3
Attack: Bite
Fire-bleching dragon:
Strength: 8, Speed: 5
Attack: Bite and Fire Ball
Ice dragon:
Strength: 5, Speed: 8
Attack: Bite and Ice Ball
Magic dragon:
Strength: 4, Speed: 4
Attack: Bite
Magic ice dragon:
Strength: 6, Speed: 9
Attack: Bite and Ice Ball
Magic attack from magic dragon: Magic lightning

Use when

You have:

  • An existing component class that may be unavailable for subclassing

You want to:

  • Attach additional state or behavior to an object dynamically.
  • Make changes to some objects in a class without affection others.
  • Avoid subclassing because too many classes could result.

But consider using instead:

  • The Adapter pattern, which sets up an interface between different classes.
  • The Composite pattern, which aggregates an object without also inheriting its interface.
  • The Proxy pattern, which specifically controls access to objects.
  • The Strategy pattern, which changes the original object rather than wrapping it.

Bibliography

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s