Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 789
Lijin Durairaj Avatar asked Oct 27 '16 21:10

Lijin Durairaj


People also ask

What are decorators in design patterns?

Decorator is a structural design pattern that lets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors.

How does a decorator pattern work?

Decorator pattern allows a user to add new functionality to an existing object without altering its structure. This type of design pattern comes under structural pattern as this pattern acts as a wrapper to existing class.

What is the decorator pattern used for?

The Decorator Pattern allows class behavior to the decorated dynamically. It's a structural design pattern as it's used to form large object structures across many disparate objects. The concept of decorator is that it adds additional attributes to an object dynamically.

What problem is solved by the decorator pattern?

The problem of inheritance can be solved by using a decorator pattern where you can add functionality to an object at run time.


2 Answers

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

For example, you have an 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 written by someone else

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

And once you decided, that ALL calls to repository should be logged. But you have a problem: the Repository class is from an external library and you don't want to change that code. So you need to extend the Repository's behavior that you use. You write RepositoryLogDecorator : IRepository, and inside on each method do the 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.DoSomething(new Repository());

but now you can use

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

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

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

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

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

you will be able to automatically 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

like image 52
tym32167 Avatar answered Oct 19 '22 01:10

tym32167


There is this PatternCraft series on Youtube that explains Design Patterns with Starcraft, you should check the video about Decorators here.

In the video above the author gives an example with a Marine and WeaponUpgrade.

In the game you will have a Marine and then you can upgrade its weapon:

marine = new WeaponUpgrade(marine);

Note that you still have a marine there, it is not a new unit, it is the same unit with things that modifies its attributes.

public class MarineWeaponUpgrade : IMarine
{
    private IMarine marine;

    public MarineWeaponUpgrade(IMarine marine)
    {
        this.marine = marine;
    }

    public int Damage
    {
        get { return this.marine.Damage + 1; } // here
        set { this.marine.Damage = value; }
    }
}

You do that by creating a class that implements the same interface as your unit and access your unit properties to modify values.

There is a Kata on CodeWars challenging you to complete the Weapon and Armor decorators for a marine.

like image 15
BrunoLM Avatar answered Oct 19 '22 00:10

BrunoLM