Dan*_*ull 10 .net design-patterns stream reliability
.NET中使用了一种相当常见的模式来测试类的功能.这里我将使用Stream类作为示例,但该问题适用于使用此模式的所有类.
该模式是提供一个名为CanXXX的布尔属性,以指示该类上的功能XXX可用.例如,Stream类具有CanRead,CanWrite和CanSeek属性,以指示可以调用Read,Write和Seek方法.如果属性值为false,则调用相应的方法将导致抛出NotSupportedException.
从流类的MSDN文档:
根据底层数据源或存储库,流可能仅支持其中一些功能.应用程序可以使用CanRead,CanWrite和CanSeek属性查询流的功能.
和CanRead属性的文档:
在派生类中重写时,获取一个值,指示当前流是否支持读取.
如果从Stream派生的类不支持读取,则对Read,ReadByte和BeginRead方法的调用会抛出NotSupportedException.
我看到很多代码都是按照以下方式编写的:
if (stream.CanRead)
{
stream.Read(…)
}
Run Code Online (Sandbox Code Playgroud)
请注意,没有同步代码,例如,以任何方式锁定流对象 - 其他线程可能正在访问它或它引用的对象.也没有捕获NotSupportedException的代码.
MSDN文档未声明属性值不能随时间更改.实际上,当流关闭时,CanSeek属性会更改为false,从而演示这些属性的动态特性.因此,没有合同保证在上面的代码片段中调用Read()不会抛出NotSupportedException.
我希望有很多代码可以解决这个潜在的问题.我想知道那些发现这个问题的人是如何解决它的.这里适合哪些设计模式?
我也很感激评论这种模式的有效性(CanXXX,XXX()对).对我来说,至少在Stream类的情况下,这代表了一个试图做太多的类/接口,应该分成更基本的部分.缺乏紧密的,有文件记录的合同使测试变得不可能,实施更加困难!
如果不了解对象的内部结构,您必须假设在多个线程中修改对象时,“标志”属性太不稳定而无法依赖。
我发现这个问题关于只读集合比流更常见,但我觉得这是相同设计模式的另一个例子,并且适用相同的论点。
澄清一下,.NET 中的 ICollection 接口具有 IsReadOnly 属性,该属性旨在用作集合是否支持修改其内容的方法的指示符。就像流一样,该属性可以随时更改,并会导致抛出 InvalidOperationException 或 NotSupportedException。
围绕这个问题的讨论通常可以归结为:
模式很少是一件好事,因为你被迫处理不止一组“行为”;拥有可以随时切换模式的东西要糟糕得多,因为您的应用程序现在也必须处理多个“一组”行为。然而,仅仅因为可以将某些东西分解为更谨慎的功能并不一定意味着您总是应该这样做,特别是当将其分解并不能降低手头任务的复杂性时。
我个人的观点是,你必须选择最接近你认为同级消费者能够理解的心理模型的模式。如果您是唯一的消费者,请选择您最喜欢的型号。就 Stream 和 ICollection 而言,我认为对它们有一个单一的定义更接近于类似系统中多年开发所建立的心智模型。当您谈论流时,您谈论的是文件流和内存流,而不是它们是否可读或可写。同样,当您谈论集合时,您很少用“可写性”来提及它们。
我对此的经验法则是:始终寻找一种方法将行为分解为更具体的界面,而不是拥有操作“模式”,只要它符合简单的心理模型即可。如果很难将单独的行为视为单独的事物,请使用基于模式的模式并非常清楚地记录它。
| 归档时间: |
|
| 查看次数: |
1093 次 |
| 最近记录: |