Liskov替换原理和Streams

时间:2013-11-29 17:30:38

标签: c# oop stream solid-principles liskov-substitution-principle

是否存在无法编写或寻求的Stream派生类会破坏Liskov替换原则吗?

例如,无法搜索NetworkStream,如果调用方法NotSupportedException,则会抛出Seek

或者因为CanSeek标志的存在可以吗?

考虑到Square继承自Rectangle的众所周知的示例...将DoesHeightAffectsWidthDoesWidthAffectsHeight添加到Rectangle以解决问题?

这不是通过添加标志来打开固定东西的大门吗?

2 个答案:

答案 0 :(得分:7)

CanSeek从技术上讲使流类不会违反LSP。只有当它返回真实时,才会寻求工作的承诺。

我个人认为它是ISP的严重弯曲,可能是SRP,而我的内部设计师更喜欢像SeekableStream子类/接口这样的可寻找流可以继承的东西。但我确信这带来了自己的问题(例如,在有时可寻找的流中)......坦率地说,现实世界的可用性胜过原则。

这是要记住的事情。偶尔,原则与现实相互碰撞。在大多数情况下,SOLID原则有助于最大限度地减少不必要的复杂性,并且通常可以保持OO系统的可维护性并防止它们在自身重量下崩溃。如果纯度导致系统更多复杂,但是 - 例如,因为现在只有有时可寻找的流不能很好地适应层次结构 - 那么偶尔可能会出现一些丑陋的情况。合理的。

但它永远不应该是第一选择,因为法律条文允许它。 SOLID原则不仅仅是规则;他们是原则。他们是法律背后的理念 - 精神。如果你在通过精神律师的过程中坚持这封信,那么你就错过了原则的全部要点。

至于Square / Rectangle问题......从技术上讲,确定改变高度的属性/函数是否也会改变宽度,可以考虑与LSP的字母保持一致。尽管如此,感觉就像律师一样,并且正在推动其他SOLID原则的界限。从现实的角度来看,它绝对不是最佳解决方案,因为它增加了复杂性并引入了偶然副作用的可能性;现在,想要说rect.Height = 50;的所有内容也会无意中改变宽度。

答案 1 :(得分:5)

Can...方法意味着Stream不会破坏LSP。 Stream提供功能进行读取,写入和搜索,但没有保证任何实现类都将遵守它。 Can...方法使这成为Stream契约的显式特征 - 派生类必须实现它们,以允许客户端代码在调用之前检查派生类是否实现某些行为。因此,尝试写入Stream的任何代码都应该在调用CanWrite之前检查Write,这可以通过Stream的任何正确实现的派生来完成。因此,它们可以互换,因为LSP需要。

我认为添加标记派生类是否实现某个特定功能的方法肯定会被滥用 - 如果一个团队没有纪律,他们最终可能会有一个非常广泛,臃肿的界面打破ISP。我认为StreamIList<T>在这方面设计得很好 - 它们不会破坏LSP,并且它们定义了一个足够狭窄的密切相关行为的合同以留在ISP中。显然,他们的设计已被考虑过了。

我认为,如果Square继承自Rectangle,您当然可以添加DoesHeightAffectsWidthDoesWidthAffectsHeight来解决问题,但团队必须决定是否可接受的,或者这些方法的添加是否会破坏ISP。增加AreAllInternalAnglesEqual来支持梯形太远了吗?在某种程度上,这取决于编写代码的工程师。