Lijin John Lijin John - 1 month ago 7
C# Question

Understanding Decorator Design Pattern in C#

I just started to learn Decorator Design Pattern, unfortunately i had to go through various refrences to understand the Decorator pattern in a better manner which led me in great confusion. so, as far as my understanding is concern, i believe this is a decorator pattern

interface IComponent
{
void Operation();
}
class Component : IComponent
{
public void Operation()
{
Console.WriteLine("I am walking ");
}
}
class DecoratorA : IComponent
{
IComponent component;
public DecoratorA(IComponent c)
{
component = c;
}
public void Operation()
{
component.Operation();
Console.WriteLine("in the rain");
}
}
class DecoratorB : IComponent
{
IComponent component;
public DecoratorB(IComponent c)
{
component = c;
}
public void Operation()
{
component.Operation();
Console.WriteLine("with an umbrella");
}
}
class Client
{
static void Main()
{
IComponent component = new Component();
component.Operation();

DecoratorA decoratorA = new DecoratorA(new Component());
component.Operation();

DecoratorB decoratorB = new DecoratorB(new Component());
component.Operation();

Console.Read();
}
}


but can the below code also be Decorator Pattern?

class Photo
{
public void Draw()
{
Console.WriteLine("draw a photo");
}
}
class BorderedPhoto : Photo
{
public void drawBorder()
{
Console.WriteLine("draw a border photo");
}
}
class FramePhoto : BorderedPhoto
{
public void frame()
{
Console.WriteLine("frame the photo");
}
}
class Client
{
static void Main()
{
Photo p = new Photo();
p.Draw();

BorderedPhoto b = new BorderedPhoto();
b.Draw();
b.drawBorder();

FramePhoto f = new FramePhoto();
f.Draw();
f.drawBorder();
f.frame();
}
}


My Understanding

from the second example given by me, we can call all the three methods, but from the first example i wont be able to get access to all the three methods by creating a single object.

Answer

It should be a comment, but I have too much words.

For example, you have a object and interface, like Repository : IRepository.

public interface IRepository
{
    void SaveStuff();
}

public class Repository : IRepository
{
    public void SaveStuff()
    {
        // save stuff   
    }
}

and client, which probably was writen not by you

class RepoClient
{
    public void DoSomethig(IRepository repo)
    {
        //...
        repo.SaveStuff();
    }
}

And once you decided, that ALL calls to repository should be logged. But you have a problem - Repository - class from external library and you dont want to change that code. So you need to extend behavior of Repository, which you using. You write RepositoryLogDecorator : IRepository, and inside on each method do logging, like

public class RepositoryLogDecorator  : IRepository
{
    public IRepository _inner;

    public RepositoryLogDecorator(IRepository inner)
    {
        _inner = inner;
    }

    public void SaveStuff()
    {
        // log enter to method
        try
        {
            _inner.SaveStuff();
        }
        catch(Exception ex)
        {
            // log exception
        }       
        // log exit to method
    }
}

So, before you could use client as

var client = new RepoClient();
client.DoSomethig(new Repository());

but now you can use

var client = new RepoClient();
client.DoSomethig(new RepositoryLogDecorator(new Repository()));

Note, that this is very simple example. In real projects, where object created primary with DI container, you able to use decorator by changing some config.

So, what for decorator is used: to extend functionality of object without changing object or client.

Another benefit of decorator: your decorators does not depends on Repository implementation. Only depends from interface IRepository. Why this is advantage? If somewhen you will decide to write you own implementation

public class MyAwesomeRepository : IRepository
{
    public void SaveStuff()
    {
        // save stuff, but AWESOME!
    }
}

you automatically able to decorate this with decorator, which already exist

var client = new RepoClient();
client.DoSomethig(new RepositoryLogDecorator(new MyAwesomeRepository()));

Want to see example from real software? (just as sample, code is ugly, I know) => go here

Cool! Love it! :D

Comments