装饰模式,通过继承或依赖注入?

时间:2017-12-11 04:06:48

标签: c# design-patterns decorator

现在我正在研究常见的设计模式,并且在很大程度上我理解装饰器模式的目的。但是我不能得到的是,在装饰器类中包装现有对象的目的是什么?

考虑这种情况,因为Progress是观察者模式的一部分,我想限制其订阅者的更新量,以防止UI线程锁定。

所以我将类修饰为每50毫秒更新一次。

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;

        }
    }

两个类都完成了同样的事情,除了我发现第一个版本更好,因为它允许我使用基础构造函数来设置进度更新的委托。基类已经支持覆盖该方法,那么我需要包装该对象吗?

这两个类都是装饰模式的例子吗?我宁愿使用第一个选项,但我很少以这种方式看到例子。

1 个答案:

答案 0 :(得分:4)

想象一下,n接口有IProgress<T>个不同的实现。

为了这个例子,我们考虑两个实现:

  • EndpointProgress<T>,这会在每次响应不同时轮询端点和Report
  • QueryProgress<T>,每次结果不同时,会定期执行数据库查询并Report

为了使用您的第一种方法限制这两种实现,您必须创建ProgressThrottle<T>的两个实现,一个继承自EndpointProgress<T>,另一个继承自{{} 1}}。

为了使用第二种方法限制这两种实现,您只需使用QueryProgress<T>EndpointProgress<T>的包装实例。

QueryProgress<T>

编辑:

  

所以在一个场景中,我确信我不会多次扩展一个类来添加功能,不使用包装器是否可以接受?

我仍然会使用装饰器的第二个实现(我甚至不确定第一个实现是否会被视为装饰器模式)有几个原因:

  • S.O.L.I.D.原则&#39; open/closed principle声明:

      

    软件实体(类,模块,函数等)应该是可以扩展的,但是关闭以进行修改。

    我必须修改您当前的var throttledEndpointProgress = new ProgressThrottle2<int>(new EndpointProgress<T>()); var throttledQueryProgress = new ProgressThrottle2<int>(new QueryProgress<T>()); 实施以扩展它,您违反了开放/已关闭。

  • Progress继承ProgressThrottle意味着每次Progress&#39;构造函数更改,Progress也需要更改其构造函数。

  • 通过使用包装装饰器,您可以组合和组合装饰器。让我们考虑记录每ProgressThrottle次呼叫的IProgress<T>实施。你可以 - 基于配置,环境等 - 以不同的方式组成这些装饰器以实现不同的目标:

    onReport

    此处,var progress1 = new LoggingProgress<int>( new ProgressThrottle<int>(new Progress<int>()) ); var progress2 = new ProgressThrottle<int>( new LoggingProgress<int>(new Progress<int>()) ); 仅记录受限制的报告进度。 progress1将记录所有报告的进度,但会以受限制的方式进行报告。根据您的目标,您可能需要一个实现或另一个实现;或者你可能想要它们两个,一个用于分期诊断,另一个用于prod,但最重要的是你不必改变装饰器的实现以改变这种行为。