Decorator Pattern, through inheritance or dependency?

Now I am studying general design patterns, and for the most part I understand the purpose of the decorator pattern. But what I don’t understand, what is the purpose of wrapping an existing object in the decorator class?

Consider this scenario, since Progress is part of the observer pattern, I want to limit the number of updates for my subscribers to prevent blocking the user interface flow.

So, I decorated the class to update it only every 50 milliseconds.

public class ProgressThrottle<T> : Progress<T> { private DateTime _time = DateTime.Now; public ProgressThrottle(Action<T> handler) : base(handler) { } protected override void OnReport(T value) { if (DateTime.Now.AddMilliseconds(50) < _time) { base.OnReport(value); _time = DateTime.Now; } } } public class ProgressThrottle2<T> : IProgress<T> { private DateTime _time = DateTime.Now; private readonly IProgress<T> _wrapper; public ProgressThrottle2(IProgress<T> wrapper) { _wrapper = wrapper; } public void Report(T value) { if (DateTime.Now.AddMilliseconds(50) < _time) { _wrapper.Report(value); _time = DateTime.Now; } } 

Both classes do the same thing, except that I find the first version better because it allows me to use the base constructor to set the delegate to update progress. The base class already supports method overrides, so why should I wrap an object?

Are both classes an example decorator pattern? I would prefer to use the first option, but I rarely see examples this way.

+5
source share
1 answer

Imagine that you have n different implementations of the IProgress<T> interface.

For this example, consider two implementations:

  • EndpointProgress<T> , this will poll the endpoint and Report each time the answer is different.
  • QueryProgress<T> , this will periodically execute the database query and Report every time the result is different.

To throttle both of these implementations using your first approach, you need to create two implementations of your ProgressThrottle<T> , one inheriting from EndpointProgress<T> , and the other from QueryProgress<T> .

To throttle both of these implementations using the second approach, you just need to use a wrapped instance of EndpointProgress<T> and QueryProgress<T> .

 var throttledEndpointProgress = new ProgressThrottle2<int>(new EndpointProgress<T>()); var throttledQueryProgress = new ProgressThrottle2<int>(new QueryProgress<T>()); 

Edit:

So, in the script, I’m sure that I will not extend the class more than once to add functionality, is it permissible not to use the shell?

I will continue to use the second implementation of the decorator (I'm not even sure that the first implementation will be considered a decorator template) for several reasons:

  • S. O .LID Principles The open / closed principle states that:

    Program objects (classes, modules, functions, etc.) must be open for expansion, but closed for modification.

    I need to change the current implementation of Progress to expand it, you break Open / Closed.

  • The inheritance of ProgressThrottle inherits from Progress means that every time the Progress ' constructor is changed, ProgressThrottle also needs to change its constructor.

  • Using wrapper decorators, you can create and combine decorators. Consider the implementation of IProgress<T> , which registers every call to onReport . You can - based on configuration, environment, etc. - create these decorators in different ways to achieve different goals:

     var progress1 = new LoggingProgress<int>( new ProgressThrottle<int>(new Progress<int>()) ); var progress2 = new ProgressThrottle<int>( new LoggingProgress<int>(new Progress<int>()) ); 

    Here progress1 will only log the throttled report. progress2 will record all progress made, but will communicate with the throttle. Depending on your goals, you may need one implementation or another; or you may want both of them, one for diagnosis at the stage of setting and the other for prod, but most importantly, you do not need to change the implementation of your decorator to change this behavior.

+4
source

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


All Articles