Understanding decorator design pattern in C #

I was just starting to learn Designator Design Pattern, unfortunately, I had to go through various reflections in order to better understand the Decorator pattern, which made me very confused. therefore, as I understand it, this is a problem, I believe that this is a sample decorator.

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 following code also be a 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 I cited, we can call all three methods, but from the first example I can’t access all three methods by creating one object.

+16
source share
5 answers

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

For example, you have an object and an interface, for example Repository: IRepository .

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

and a client that was probably written by someone else

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

And as soon as you decide that ALL accesses to the repository should be registered. But you have a problem: the Repository class from an external library, and you do not want to modify this code. Therefore, you need to extend the Repository behavior that you use. You write RepositoryLogDecorator: IRepository , and inside each method RepositoryLogDecorator: IRepository 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 the 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())); 

Please note that this is a very simple example. In real projects, where the object was created primarily with a DI container, you can use the decorator by changing some settings.

Thus, the decorator is used to expand the functionality of the object without changing the object or client.

Another advantage of the decorator: your decorator is independent of the implementation of the Repository . Only depends on the IRepository interface. Why is this an advantage? If you decide to write your own implementation of IRepository

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

You can automatically decorate this with a decorator that already exists.

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

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

+33
source

There is a PatternCraft series on Youtube that talks about developing patterns with Starcraft. Video about decorators can be seen here .

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

In the game you will have Marine and then you can update his weapons:

 marine = new WeaponUpgrade(marine); 

Please note that you still have a marine, this is not a new unit, this is the same unit with things that changes 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 this by creating a class that implements the same interface as your module, and accesses the properties of your module to change values.

There is a Kata on CodeWars that forces you to complete the weapons and armor design for the marine.

+10
source

Per GOF Page Decorator Figure:

Attach additional responsibilities to the object dynamically. Decorators provide a flexible alternative to a subclass to extend functionality.

In your second example, you use inheritance to extend the behavior of the class, I believe that this is technically not a Decorator design pattern.

+4
source

The decorator pattern allows you to add specific behavior to an individual object of a given type without affecting other instances of the same type.

In your second example, which is regular inheritance, all instances of the class inherit the changed behavior.

+3
source

The second example is not a decoration pattern, since an essential element of the decorator is the fact that the object takes on one of its forms and, possibly, improves it.

In this example, instances of this example are

public DecoratorA(IComponent c) { component = c; }

In addition, the purpose of the decorator template is to create a “single” object, and then decorate it by passing it through various filters or decorators. Consequently, the direct

DecoratorA decoratorA = new DecoratorA(new Component());

Must be

DecoratorA decoratorA = new DecoratorA(component );

0
source

Source: https://habr.com/ru/post/1011790/


All Articles