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

考虑这种情况,因为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;

        }
    }

除了我发现第一个版本更好之外,这两个类都完成相同的事情,因为它允许我使用基本构造函数为进度更新设置委托(delegate)。基类已经支持重写方法,那么我包装对象有什么需要?

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

最佳答案

假设您有n接口(interface)的IProgress<T>不同实现。

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

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

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

    为了使用第二种方法限制这两种实现,您只需要使用包装的EndpointProgress<T>QueryProgress<T>实例即可。
    var throttledEndpointProgress = new ProgressThrottle2<int>(new EndpointProgress<T>());
    var throttledQueryProgress = new ProgressThrottle2<int>(new QueryProgress<T>());
    

    编辑:



    我仍然会使用装饰器的第二个实现(我什至不确定第一个实现是否会被视为装饰器模式),原因如下:
  • S.O.L.I.D.原则的open/closed principle指出:



    如果您要扩展它,则必须修改当前的Progress实现,这违反了“打开/关闭”。
  • ProgressThrottle继承Progress意味着每次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将仅记录受限制的报告进度。 progress2将记录所有报告的进度,但是将以节流的方式报告。根据您的目标,您可能需要一个实现或另一个实现;或者您可能想要它们两者,一个用于登台诊断,另一个用于生产,但是最重要的是,您不必更 retrofit 饰器的实现即可更改此行为。
  • 关于c# - 装饰器模式,通过继承还是依赖注入(inject)?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47746295/

    10-12 22:20