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.
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.
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.
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.
The problem of inheritance can be solved by using a decorator pattern where you can add functionality to an object at run time.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With