以下是我在界面,抽象和普通类之间的混淆 -
我知道抽象类可以有一个没有实现的方法,但是在基类中将方法声明为虚拟有什么危害,在派生类中有一些虚拟实现和重载。寻找可以验证答案的实际场景?
为什么我们需要一个接口,当我们有抽象类时,我知道接口我们可以有多个继承,并且已经了解各种理论原因,寻找抽象类无法帮助的实际场景,你必须去用于界面?
是否有抽象类,接口不是开销?
答案 0 :(得分:2)
有些情况下没有“正确”的虚拟实现。例如,在System.IO.Stream
案例(抽象类)中,Read
或Write
的合理实施是什么?扔?没做什么?或者System.Xml.XmlReader
类中的许多方法 - 对于任意XML阅读器的Depth
或Read
,什么是合理的实现?通过在类抽象(而不是虚拟)中创建方法,类的作者正在声明任何派生自该类的人必须考虑如何为这些方法做什么,并且抽象限定符强制执行这一点。
实际的原因正是你所说的 - 多重继承。例如,如果IEnumerable<T>
是一个抽象类,那么在很多情况下我们希望能够枚举对象的元素但不能,因为该对象已经从其他类继承。更理论上的原因是接口通常定义行为,而类定义了一组对象,但出于问题的目的,实际原因更加实用。
我不明白你的问题。在哪个意义上的开销?
答案 1 :(得分:2)
我觉得你的想法太难了。它就像看着叉子和勺子,担心什么时候使用。没有正确的答案,只需使用对您正在做的事情有意义的答案。到达那里的许多途径。
以下是我在现实世界中使用这些的方法(财富500强等公司......)
接口允许您为类添加任意数量的接口。它们基本上允许您根据需要绑定任何合同。它们和你一样小。我使用它的一个例子是音乐编码器服务,它只有一些简单的属性和方法,每种编码器类型都需要。我后来添加了更多的接口,因为其他要求发挥作用但我不想打破其他部分的代码,不需要知道或关心新的接口。编码器非常松散耦合并且可能有多个合同,所以这对我来说很有意义。关于接口的主要问题是当你使用它们时,不要随意更改它们,因为它会破坏接口的目的,而是创建一个新的接口。接口是插件类型开发的最佳选择。
抽象类有点酷,因为你可以在那里使用一些基础实现,但你基本上是在说“但你仍然需要这样做部分“作为该类实施此功能的责任。例如,这可以用于“保存”方法。假设您有一些以相同方式处理数据的抽象类,但您在底层抽象类中有许多共性,它们做了大量工作,但您要求每个继承类型保存自己的数据例如,需要以自己的格式。这可能与保存在facebook和twitter中的内容的网络项目或在数据库和文件系统中保存内容的其他项目相关,但核心代码始终命中一个中央数据库,表示它已保存并修改了上次日期。
很抱歉,我很无聊,很多打字。但这就是我使用它们的方式。
答案 2 :(得分:1)
每个人都有自己的目的。当您不想定义任何特定实现时,可以使用接口。它仅为对象提供“接口”,即构成公共定义的方法和属性。对象可以继承多个接口。一个很好的例子是List<>
对象。 List<>
实现了几个接口,诸如IEnumerable
,IList
,ICollection
,IEnumerable<>
,IList<>
,和ICollection<>
。
每种方法都有不同的方法和不同的属性,用于不同的目的。你不能用抽象类来做这件事。您可以将List<>
转换为任何这些接口,并在不知道它们的确切实现的情况下使用它们。这对于称为依赖注入的概念特别有用,但还有许多其他用途。
当您想要定义对象的部分实现但希望将其他部分保留到派生类时,抽象类很有用。关于抽象类的一个关键要点是它们不能自己实例化,因为它们通常缺少完整的实现,以及abstract关键字告诉编译器它无法实例化的事实。是的,你可以提供虚拟实现,但为什么呢?重点是摘要是......好的......抽象的。
想象一下,你有一个类Cat,这个类派生自一个类Animal。没有Animal对象,它只是一个“类型”。你无法实例化动物,因为在现实世界中没有真正的动物,只有动物类型的生物。您可以将不同的生物视为常见的动物类型,但不存在真正的动物,它只是一个概念。
动物将是一种抽象类型,因为动物的概念是抽象的。软件也是如此。您可能拥有对象的概念,例如Stream。它是NetworkStream吗?一个FileStream?一个MemoryStream?流只是一个概念。接口也只是一个概念,但与抽象类不同,接口不能有任何实现。
因此,将抽象类视为具有某种实现的概念,将接口视为没有任何实现的概念。