抽象类相较于接口的优势

4
我从MSDN文章中得到了以下声明。文章表明,抽象类比接口具有优势,因为可以修改抽象类以添加新成员。改变抽象类是否会使继承自它的类不稳定?或者有人能否解释一下他们的观点?
请尽量定义类而非接口。在您程序库的后续版本中,您可以安全地向类中添加新成员;但是,无法向接口中添加成员而不破坏现有代码。

2
如果您向接口添加成员,则实现旧接口的任何类都不会包括新成员,因此将不再编译。尽管对于向抽象类添加抽象成员也是如此。 - George Duckett
6个回答

7

假设您有一个接口

public interface Animal 
{
     void Sleep();
}

当您发布您的库并发现需要向接口添加属性时。

public interface Animal 
{
     int Age{get;set;}
     void Sleep();
}

每个人针对第一个版本接口编写的所有代码都将不再编译,需要进行升级。如果使用这个抽象类发布第一个版本。
public abstract class Animal 
{
    public abstract  void Sleep();
} 

现在您需要添加另一个属性。
public abstract class Animal
{
    public virtual int Age{get;set;}
    public abstract  void Sleep();
} 

在这种情况下,用户无需更改其代码。

谢谢您的回答,我们能否像您展示的属性一样更改方法...我对接口有点困惑 :( - Smack
你可以添加一个新的方法,但如果强制更改所有下游消费者,就不能更改一个方法。 - rerun

4
假设你正在编写代码并在第一个版本中使用某个接口(IExample)。 在程序的第二个版本中,你意识到IExample应该有一个名为IExample.NewMethod的方法。 如果你扩展了IExample以添加此方法,则之前编写的所有代码都将无法正常工作,因为从IExample继承的所有类都不会完全实现此接口 - 因此代码将无法编译。 只针对这种情况讨论是正确的。可以通过使用从IExample继承的新接口(INewExample)或者创建没有继承关系的新接口来解决此问题。
但是接口对于抽象类也有一些优点。 接口比抽象类更好地封装了代码的实现。 此外,您可以将接口用于不同的类,但是当您使用抽象类时,这意味着您的类在某种程度上是抽象类(例如Circle是一个Shape,因此您可以将Circle从抽象的Shape继承),但是从Car继承Circle是非常糟糕的想法,即使它们具有相同的接口。

如果想要了解接口VS抽象类的完整概述,我建议您阅读肯特·贝克的书和《代码大全》以了解继承的一般情况。


4
这并不是要求过于严格。通过接口(作为合同)进行编程确实是解耦应用程序的最佳方法。例如,创建一个接口包装器非常容易,而类甚至不必拥有单个虚拟方法。
此外,文章甚至似乎没有将抽象类与接口进行比较(因为它仅在下一个“指南”中提到它们),而是将所有类与接口进行比较。因此,如果你问我,这是一个相当模糊的指南。
这可能只对所述问题有意义:更改接口会破坏所有实现,而向类添加成员则不会。另一方面,如果更改方法的签名,那么类也不会很幸运。从安全性的角度来看,抽象类确实提供了一种确保库始终向调用者公开其自身功能的方式,仅允许在您想要的位置进行修改。使用接口时,可以传递几乎满足合同的任何代码。

0
更改抽象类是否会使继承它的类不稳定?
不一定。只要您不将新成员标记为virtual,任何当前不使用新成员的类都将能够忽略它们,因此不会出现版本问题。
他们的观点是什么?
观点是,如果您向接口添加新成员,则实现该接口的任何类立即会出现问题,因为它没有实现新成员。但是,向抽象类添加成员不会导致构建中断。

4
你肯定是指“抽象”,而不是“虚拟”。 - Olivier Jacot-Descombes
我实际上是指两者(并且abstract成员总是virtual,因此virtual涵盖了两种情况)。考虑具有属性ABC的类Base。如果一个类Derived : Base包含成员D,然后Base添加了virtual成员D,那么Derived现在将编译出警告,就像http://msdn.microsoft.com/en-us/library/aa288479(v=vs.71).aspx中的`Meth3`示例一样。 - Adam Mihalcin
好的,你是说存在名称冲突的情况。 - Olivier Jacot-Descombes
@OlivierJacot-Descombes 说得对,因为如果你允许其他人子类化你的抽象类,那么你就无法控制他们为自己的成员使用哪些名称。 - Adam Mihalcin

0

抽象类最大的优点是可以拥有内部成员,而接口则不行。另一方面,你可以在接口上实现多重继承,但在抽象类上则不行。


严格来说,你所指的并不是真正的“多重继承”——即使使用接口,你也不是从多个基类继承——你只是实现了多个接口。这是微小但重要的区别。 - marc_s

0

抽象类的优点在于可以实现通用功能。使用接口时,每个实现类都必须提供其定义操作的自己实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接