首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Liskov替换原则是否也适用于实现接口的类?

Liskov替换原则是否也适用于实现接口的类?
EN

Stack Overflow用户
提问于 2012-09-04 02:06:29
回答 3查看 3.6K关注 0票数 6

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

2)如果确实是这样,那么如果反对使用继承的主要原因之一是由于不符合LSP的风险,那么为什么对接口进行编程被认为是一件好事(顺便说一句,我知道对接口进行编程会增加松散耦合)?也许是因为:

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

b)与继承相比,类(实现接口)不附加到LSP的可能性要小得多

谢谢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-09-04 02:11:46

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

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

如果确实是这样,那么为什么对接口编程被认为是一件好事(顺便说一句,我知道对接口编程会增加松散耦合),如果反对使用继承的主要原因之一是由于不符合LSP的风险?也许是因为:

它不是关于一个接口或一个类。这是关于违反合同的事。假设您在IVehicle (或VehicleBase)中有一个Break()方法。任何人打电话都会认为这辆车会坏掉。想象一下,如果其中一个实现没有崩溃,会有多大的惊喜。这就是LSP的全部内容。

a)松散耦合的好处大于不符合LSP的风险

嗯?

LSP b)与继承相比,类(实现接口)不附加到

的可能性要小得多。

嗯?

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

更新

--通过继承,虚方法可能会消耗私有成员,而覆盖这些虚方法的子类不能访问私有成员。

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

另外,派生类继承了父类的上下文,因此将来对父类的更改等可能会破坏它。

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

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

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

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

票数 7
EN

Stack Overflow用户

发布于 2016-01-26 04:47:47

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

代码语言:javascript
运行
复制
interface ICalculation 
{ 
    double Calculate(double A, double B); 
} 

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

代码语言:javascript
运行
复制
var myBrakableCar = MyCar as IBrakable;
if(myBrakableCar != null) 
{
    myBrakableCar.Brake();
}

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

我只是要创建一个新的概念-“各自的替换”:它做它在tin上所说的事情。

票数 1
EN

Stack Overflow用户

发布于 2016-01-27 15:37:51

广告1):是的。然而,很难让接口执行这些约定,而且它们确实应该这样做。

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

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

我一直在使用接口(在C#中),因为我喜欢做测试驱动开发。然后,我只希望我的模拟和相应的实现不会违反LSP,因为当它们违反LSP时,我的测试套件就不再健全(它声称可以工作,但它不是)。

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

但是,我们遇到了在C#中缺少对多重继承的支持,并且我们仍然坚持使用接口(或者只是更多的类,如果选择这种方法,您可以隐藏在SRP后面)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12252363

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档