现在我正在研究常见的设计模式,并且在很大程度上我理解装饰器模式的目的。但是我不能得到的是,在装饰器类中包装现有对象的目的是什么?
考虑这种情况,因为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;
}
}
两个类都完成了同样的事情,除了我发现第一个版本更好,因为它允许我使用基础构造函数来设置进度更新的委托。基类已经支持覆盖该方法,那么我需要包装该对象吗?
这两个类都是装饰模式的例子吗?我宁愿使用第一个选项,但我很少以这种方式看到例子。
答案 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,但最重要的是你不必改变装饰器的实现以改变这种行为。