9

存在无法编写或查找的Stream派生类这一事实是否违反了 Liskov 替换原则?

例如,无法查找 NetworkStreamNotSupportedException ,如果调用该方法,它会抛出一个Seek

还是因为CanSeekflag的存在就ok了?

Square考虑到从...继承的众所周知的示例,Rectangle是否会添加标志DoesHeightAffectsWidthDoesWidthAffectsHeight解决Rectangle问题?

这不是为通过添加标志来修复问题打开了大门吗?

4

2 回答 2

7

CanSeek技术上防止流类违反 LSP。只有当它返回真时,寻求承诺才会起作用。

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

这是需要牢记的。有时,原则和现实会发生冲突。在大多数情况下,SOLID 原则有助于最大限度地减少不必要的复杂性,并且通常保持 OO 系统可维护并防止它们因自身重量而崩溃。但是,如果纯度导致系统更加复杂——例如,因为现在只有有时可搜索的流不能很好地融入层次结构——那么偶尔的丑陋也许是合理的。

但它绝不应该仅仅因为法律条文允许就成为首选。SOLID 原则不仅仅是规则;他们是原则。它们是文字背后的思想——法律的精神。如果你在用律师的方式超越精神时坚持信条,那么你就错过了原则的全部要点。

至于方形/矩形问题......从技术上讲,可以考虑具有确定改变高度是否也会改变宽度的属性/函数,以符合 LSP 的字母。不过,再一次,它感觉就像是在做律师,并且正在推动其他 SOLID 原则的界限。从现实的角度来看,这也绝对不是最佳解决方案,因为它增加了复杂性并引入了意外副作用的可能性;现在所有想说的rect.Height = 50;都可以无意中改变宽度。

于 2013-11-29T17:41:56.243 回答
5

这些Can...方法意味着Stream不会破坏 LSP。Stream提供读取、写入和查找的能力,但不保证任何实现类都会尊重它。这些Can...方法使它成为Stream契约的一个显式特性——派生类必须实现它们以允许客户端代码在调用之前检查派生类是否实现了某些行为。因此,任何尝试写入 a 的代码Stream都应该CanWrite在调用之前进行检查Write,例如,这可以通过任何正确实现的Stream. 因此,它们可以根据 LSP 的要求互换。

我认为添加方法来标记派生类是否实现特定功能可能会被滥用,这当然是正确的——如果一个团队没有纪律,他们最终可能会得到一个非常广泛、臃肿的接口,从而破坏 ISP。我认为这一点Stream并且IList<T>在这方面设计得很好——它们不会破坏 LSP,并且它们定义了一个足够狭窄的密切相关行为的合同以留在 ISP 内。显然,他们的设计已经被考虑过了。

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

于 2013-11-29T17:43:37.960 回答