[X]

C# Decorator Pattern - Design Patterns in Action

 

Decorator Design Pattern

What is Decorator Pattern?

Decorator expands the functionality of an instance of class without changing the class code. It provides a way to attach new state and behavior to an object dynamically. The object does not know it is being decorated. It takes and existing object and adds new functionality to it.
We can take example of a window which can be decorated with a scroll bar if the content displayed on the window is gets over-flowed. Also we can think example of decorating an existing image with border/watermark at runtime. So we can see that the beauty of this pattern is:

  • The original object is unaware of decoration.
  • Now we don't need to create one big class full of all the features, rather we can decorate the object at runtime mixing the decorations to them.


So what are the various essential players to the decorator pattern?

Component:

Original class(es) which are going to be expanded by adding new features to them.

Operation:

An interface IComponent, which contains the operations which can be replaced.

Decorator:

A class which implements/inherits from IComponent and adds state and/or behaviour to the Component.

Decorator pattern has 2 kind of relationship:

Is-a

Decorator inherits of IComponent and can be used in place of IComponent by client.

Has-a

Decorator instantiates one or more IComponent objects, decorates them and they can be replace the original IComponent objects.

Lets start with an example where we have an image component and we want to watermark the image.

Below is our high level intention what we are going to do and what we want to achieve by this decorator pattern.

IPhoto: any image

Photo: a plain image

Operation: Display image

Decorator: A watermarked image

Client: creator of image and watermarked image


1. Create a C# Class Library project and name it "DecoratorPattern".

2. Add IPhoto.cs interface and code below lines: 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecoratorPattern
{
    public interface IPhoto
    {
        string DisplayImage();
    }
}

 

 

3. Add Photo.cs class implementing IPhoto interface and code below lines:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecoratorPattern
{
    public class Photo:IPhoto
    {
        public string DisplayImage()
        {
            return "plain image.";
        }
    }
}

 

4. Add WatermarkedPhoto.cs class implementing IPhoto interface and code below lines:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecoratorPattern
{
    public class WatermarkedPhoto:IPhoto
    {
        IPhoto originalPhoto;
        public WatermarkedPhoto(IPhoto photo)
        {
            originalPhoto = photo;
        }
        public string DisplayImage()
        {
            return "watermaked " + originalPhoto.DisplayImage();
        }
    }
}

 

 

5. Create a C# Console project with name of "DecoratorPatternClient" and add reference to the "DecoratorPattern" project.

6. Rename the program.cs file as "DecoratorClient.cs" and write below code:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DecoratorPattern;

namespace DecoratorPatternClient
{
    class DecoratorClient
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Example of decorator pattern:\n\r");

            IPhoto photo = new Photo();
            Console.WriteLine(DisplayImage(photo));

            //now lets see the decorated image
            Console.ReadLine();
            IPhoto decoratedPhoto=new WatermarkedPhoto(photo);
            Console.WriteLine(DisplayImage(decoratedPhoto));
            Console.ReadLine();

        }

        static string DisplayImage(IPhoto p)
        {
            return "I am " + p.DisplayImage();
        }
    }
}

 

 

7. And the output looks like below:

We saw that how decorator pattern can be used to expand the existing class funcionality without changing any of its existing code. So next time when we program by intention that this class may be extended in future we can think of implementing decorator design pattern.

blog comments powered by Disqus

Posts By Month