7

1) Does LSP also apply to interfaces, meaning that we should be able to use a class implementing a specific interface and still get the expected behavior?

2) If that is indeed the case, then why is programming to an interface considered a good thing ( BTW- I know that programming to an interface increases loose coupling ), if one of the main reasons against using inheritance is due to risk of not complying to LSP? Perhaps because:

a) benefits of loose coupling outweight the risks of not complying to LSP

b) compared to inheritance, chances that a class ( implementing an interface ) will not adher to LSP are much smaller

thank you

4

3 回答 3

9

LSP 是否也适用于接口,这意味着我们应该能够使用实现特定接口的类并仍然获得预期的行为?

LSP 适用于合同。契约可以是一个类或一个接口。

如果情况确实如此,那么为什么对接口进行编程被认为是一件好事(顺便说一句-我知道对接口进行编程会增加松散耦合),如果反对使用继承的主要原因之一是由于不遵守的风险语言服务提供商?也许是因为:

这与接口或类无关。这是关于违反合同的。假设您在( 或)中有一个Break()方法。任何打电话给它的人都会认为这辆车会坏掉。想象一下,如果其中一个实现没有中断,会有什么惊喜。这就是 LSP 的全部意义所在。IVehicleVehicleBase

a) 松耦合的好处超过了不遵守 LSP 的风险

嗯?

b) 与继承相比,类(实现接口)不遵守 LSP 的机会要小得多

嗯?

您可能想阅读我的 SOLID 文章以更好地理解原理:http: //blog.gauffin.org/2012/05/solid-principles-with-real-world-examples/

更新

详细说明 - 继承虚拟方法可能会消耗私有成员,覆盖这些虚拟方法的子类无权访问。

是的。那挺好的。成员(字段)应始终受到保护(= 声明为私有)。只有定义它们的类才真正知道它们的值应该是什么。

此外,派生类从父类继承上下文,因此可能会被未来对父类的更改等破坏。

这违反了开放/封闭原则。即通过改变行为来改变类契约。类应该扩展而不是修改。当然,这不可能一直存在,但更改不应使类的行为有所不同(除了错误修复)。

因此,我觉得让子类遵守合同比让实现接口的类遵守合同更难

为什么通过继承进行扩展很难有一个共同的原因。那是因为这种关系不是真正的is-a关系,而是开发人员只想利用基类功能。

那是错误的。那么最好使用组合。

于 2012-09-03T18:11:45.727 回答
1

我目前正在将我的代码实践与 LSP 进行比较/对比。我认为这必须与期望和决定如何定义应该期望的内容有关。我不相信替换总是意味着同样的事情。例如,如果我定义

interface ICalculation 
{ 
    double Calculate(double A, double B); 
} 

为了定义class Add : ICalculation、和class Subtract : ICalculation,我相信这些类应该执行各自的,但是,我不认为它们都应该通过相同的单元测试。我喜欢使用接口来实现可扩展性,每个扩展都有不同的功能。在汽车制动的情况下,我会给类提供接口 IBrakable 并执行以下操作: class Multiply : ICalculationclass Divide : ICalculationCalculation(A, B)

var myBrakableCar = MyCar as IBrakable;
if(myBrakableCar != null) 
{
    myBrakableCar.Brake();
}

我相信类的使用应该是可预测的,但也是有用的。有用是最重要的。

我只是要创建一个新概念 - “Respective Substition”:它会按照它在锡上所说的那样做。

于 2016-01-25T20:47:46.747 回答
0

广告 1):是的。但是,很难让接口强制执行合同,而且他们确实应该这样做。

广告 2):针对接口进行编程是一种权衡。正如您所指出的,接口鼓励所有具有非平凡合同的接口违反 LSP。

我相信这些是您问题的答案,或者至少我认识到这些是挑战鼓励使用界面的未回答的问题。

我一直使用接口(在 C# 中),因为我喜欢做 TDD。然后我只希望我的模拟和相应的实现不会违反 LSP,因为当他们这样做时,我的测试套件不再健全(它声称可以工作,但事实并非如此)。

有时,我会创建一个抽象基类而不是接口。抽象基类只是强制执行契约,并委托给虚拟保护方法,这些方法应该定义实际实现或在单元测试期间被模拟。事实证明,这在某些应用程序中很有用,在这些应用程序中会发现单元测试本身的错误。

但是后来我们遇到了在 C# 中缺少对多重继承的支持,无论如何我们都被接口卡住了(或者只是更多的类,如果你选择这种方法,你可以隐藏在 SRP 后面)

于 2016-01-27T07:37:51.360 回答