接口vs基类
什么时候应该使用接口,何时应该使用基类?
如果我不想实际定义方法的基本实现,它应该总是一个接口吗?
如果我有一个狗和猫课。 为什么要实现IPet而不是PetBase? 我可以理解为ISheds或IBarks(IMakesNoise?)的接口,因为这些可以放在一个宠物的宠物的基础上,但我不明白哪个用于通用的宠物。
让我们来看一个Dog和一个Cat类的例子,让我们用C#来说明:
狗和猫都是动物,特别是四足哺乳动物(动物是一般的)。 让我们假设你有一个抽象类哺乳动物,他们两个:
public abstract class Mammal
这个基类可能会有默认的方法,例如:
- 饲料
- 伴侣
所有这些行为在两个物种之间或多或less具有相同的实现。 要定义这个,你将有:
public class Dog : Mammal public class Cat : Mammal
现在假设还有其他的哺乳动物,我们通常会在动物园看到:
public class Giraffe : Mammal public class Rhinoceros : Mammal public class Hippopotamus : Mammal
这仍然是有效的,因为Feed()
和Mate()
函数的核心仍然是相同的。
然而,长颈鹿,犀牛和河马不是完全的动物,你可以制造宠物。 这是一个接口将会有用的地方:
public interface IPettable { IList<Trick> Tricks{get; set;} void Bathe(); void Train(Trick t); }
上述合同的执行情况在猫狗之间是不一样的, 把他们的实现放在一个抽象类inheritance将是一个坏主意。
你的狗和猫的定义现在应该是这样的:
public class Dog : Mammal, IPettable public class Cat : Mammal, IPettable
理论上讲,你可以从一个更高级的基类中覆盖它们,但是本质上来说,一个接口允许你仅仅把你需要的东西添加到一个类中,而不需要inheritance。
因此,因为通常只能从一个抽象类inheritance(在大多数静态types的OO语言中,它们是包含C ++的exception),但是能够实现多个接口,因此它允许您严格按照需要构build对象。
那么,乔希布洛赫自己在有效的Java 2D :
比抽象类更喜欢接口
一些要点:
现有的类可以很容易地改进来实现一个新的界面 。 你所要做的就是添加所需的方法,如果它们还不存在的话,并向类声明中添加一个implements子句。
接口是定义mixin的理想select 。 一般来说,mixin是一种类,除了“主types”外,类还可以声明它提供了一些可选的行为。 例如,Comparable是一个mixin接口,它允许一个类声明它的实例相对于其他可相互比较的对象是有序的。
接口允许构build非分层types的框架 。 types层次对于组织某些事物来说是很好的,但是其他的东西并不是整齐地落入僵化的层次结构中。
接口通过包装类成语实现了安全,强大的function增强 。 如果你使用抽象类来定义types,你可以让程序员想要添加function,只能使用inheritance。
而且,通过提供一个抽象的骨架实现类来与你导出的每个非平凡接口一起使用,你可以将接口和抽象类的优点结合起来。
另一方面,接口很难发展。 如果你添加一个方法到一个接口,它将打破所有的实现。
PS:买书。 这是更详细的。
现代风格是定义IPet 和 PetBase。
接口的优点是其他代码可以使用它,没有任何关系到其他可执行代码。 完全“干净”。 接口也可以混合使用。
但是基类对于简单的实现和通用工具是有用的。 所以提供一个抽象的基类以节省时间和代码。
接口和基类表示两种不同的关系forms。
inheritance (基类)表示一个“是”的关系。 例如,狗或猫是“宠物”。 这种关系总是代表了class级的(单一) 目的 (结合“单一责任原则” )。
另一方面, 接口代表了一个类的附加function 。 我把它称为“是”关系,就像“ Foo
是一次性的”,因此C#中的IDisposable
接口。
一般来说,你应该使用接口而不是抽象类。 使用抽象类的一个原因是如果你在具体类中有共同的实现。 当然,你仍然应该声明一个接口(IPet)并且有一个抽象类(PetBase)来实现这个接口。使用小的,不同的接口,你可以使用倍数来进一步提高灵活性。 接口允许跨越边界的types的最大灵活性和可移植性。 当跨越边界传递引用时,总是传递接口而不是具体types。 这允许接收端确定具体的实现并提供最大的灵活性。 在以TDD / BDD方式编程时,这是绝对正确的。
“四人帮”在他们的书中写道:“因为inheritance揭示了一个子类的细节,所以常常说”inheritance破坏了封装“。 我相信这是真的。
接口
- 定义2个模块之间的合同。 不能有任何的实现。
- 大多数语言允许你实现多个接口
- 修改界面是一个突破性的改变。 所有的实现都需要重新编译/修改。
- 所有成员都是公开的。 实现必须实现所有成员。
- 接口有助于解耦。 您可以使用模拟框架来嘲笑界面背后的任何东西
- 接口通常表示一种行为
- 接口实现是相互解耦/隔离的
基类
- 允许你添加一些你可以通过派生免费获得的默认实现
- 除了C ++,你只能从一个类派生。 即使可能来自多个class级,通常也是一个坏主意。
- 改变基类相对容易。 派生不需要做任何特别的事情
- 基类可以声明可以被派生访问的受保护和公共函数
- 抽象基类不能像接口一样轻易地被模拟
- 基类通常指示types层次结构(IS A)
- 类派生可能取决于一些基本行为(对父实现有复杂的知识)。 如果你改变一个人的基本实现并打破其他人,事情可能会变得混乱。
这很适合.NET,但框架devise指南(Framework Design Guidelines)指出,一般来说,类在不断发展的框架中给予更多的灵活性。 一旦接口出货,你就没有机会改变它,而不会破坏使用该接口的代码。 然而,对于一个类,您可以修改它,而不是破坏链接到它的代码。 只要你做出正确的修改,包括增加新的function,你将能够扩展和发展你的代码。
Krzysztof Cwalina在第81页上说:
在.NET Framework的三个版本中,我已经和我们团队中的很多开发人员讨论过这个指南。 其中许多人,包括最初不同意这些指导方针的人,都表示,他们很遗憾把一些API作为一个接口。 我甚至没有听说过有一个案子,有人对他们上课感到遗憾。
这就是说,确实有一个接口的地方。 作为一般指南,总是提供一个接口的抽象基类实现,如果没有别的作为实现接口的方式的例子。 在最好的情况下,基类将节省大量的工作。
胡安,
我喜欢将界面视为表征类的一种方式。 一个特定的狗品种,比如YorkshireTerrier,可能是父级狗的后代,但它也是实施IFurry,IStubby和IYippieDog。 所以这个类定义了什么类,但是接口告诉我们关于它的一些事情。
这样做的好处是它可以让我把所有的IiippieDog都收集起来扔进我的海洋系列。 所以现在我可以跨越一组特定的对象,find符合我所看到的标准的对象,而无需太紧密地检查课程。
我发现接口确实应该定义一个类的公共行为的子集。 如果它为所有实现的类定义了所有的公共行为,那么它通常不需要存在。 他们不告诉我任何有用的东西。
这个想法虽然与每个类都应该有一个接口并且应该编码到接口的想法背道而驰。 这很好,但是你最终会遇到很多一对一的接口,这使得事情变得混乱。 我明白这个想法是不需要花费任何东西的,现在你可以轻松地进行交换。 但是,我发现我很less这样做。 大多数情况下,我只是修改现有的课程,并且如果该课程的公共接口需要更改,我总是会做同样的问题,除非我现在必须在两个地方进行更改。
所以,如果你像我这样想,你肯定会说猫和狗是可持续的。 这是一个表征,他们都匹配。
另一个这个虽然是他们应该有相同的基类? 问题是他们是否需要被广泛地视为同一件事。 当然,他们都是动物,但是这符合我们如何一起使用它们。
说我想收集所有的动物类,把它们放在我的方舟容器。
还是他们需要成为哺乳动物? 也许我们需要一些交叉动物挤奶工厂?
他们甚至需要联系在一起吗? 知道他们都是可持续的吗?
当我真的只需要一个class级时,我经常感到要获得一个全class级的愿望。 我希望有一天我可能需要它,通常我从来不会这样做。 即使我这样做,我通常会发现我必须做很多工作来解决这个问题。 那是因为我创造的第一堂课不是狗,我不是那么幸运,而是鸭嘴兽。 现在我的整个类层次都是基于奇怪的情况,我有很多浪费的代码。
你可能还会发现,并不是所有的猫都是可爱的(就像那个无毛的猫)。 现在您可以将该接口移动到所有适合的派生类。 你会发现,一个突然间的猫突然间的变化,不再是从PettableBase派生。
这里是接口和基类的基本和简单的定义:
- 基类=对象inheritance。
- Interface =functioninheritance。
干杯
我build议尽可能使用组合而不是inheritance。 使用接口,但使用成员对象进行基本实现。 这样,您可以定义一个工厂,构build您的对象以某种方式行事。 如果你想改变行为,那么你创build一个新的工厂方法(或抽象工厂),创build不同types的子对象。
在某些情况下,如果在辅助对象中定义了所有可变行为,则可能发现主对象根本不需要接口。
所以,而不是IPet或PetBase,你可能会得到一个具有IFurBehavior参数的宠物。 IFurBehavior参数由PetFactory的CreateDog()方法设置。 这是为shed()方法调用的这个参数。
如果你这样做,你会发现你的代码更灵活,你的大多数简单的对象处理非常基本的系统范围的行为。
我甚至在多种inheritance语言中推荐这种模式。
在这篇Java世界文章中有很好的解释
我个人倾向于使用接口来定义接口 – 即系统devise的一部分,指定应该如何访问某些东西。
我将有一个实现一个或多个接口的类,这并不罕见。
抽象类我用作别的基础。
以下是摘自上述文章的JavaWorld.com文章,作者Tony Sintes,04/20/01
接口与抽象类
select接口和抽象类不是一个或两个命题。 如果您需要更改devise,请将其设为界面。 但是,您可能具有提供某些默认行为的抽象类。 抽象类是应用程序框架内的优秀候选者。
抽象类让你定义一些行为; 他们强迫你的子类提供其他人。 例如,如果您有一个应用程序框架,抽象类可以提供默认服务,如事件和消息处理。 这些服务允许您的应用程序插入到您的应用程序框架。 但是,只有您的应用程序可以执行一些特定于应用程序的function。 这些function可能包括启动和closures任务,这些任务通常取决于应用程序。 因此,抽象基类可以声明抽象的closures和启动方法,而不是试图自己定义这个行为。 基类知道它需要这些方法,但抽象类让你的类承认它不知道如何执行这些操作; 它只知道它必须发起行动。 当启动的时候,抽象类可以调用启动方法。 当基类调用这个方法时,Java调用由子类定义的方法。
许多开发人员忘记了定义抽象方法的类也可以调用该方法。 抽象类是创build计划inheritance层次结构的绝佳方式。 对于类层次结构中的非叶类,它们也是一个很好的select。
类与接口
有人说你应该根据界面来定义所有的类,但是我认为推荐看起来有点极端。 当我看到devise中的某些东西会频繁变化时,我使用接口。
例如,“战略”模式可让您将新algorithm和stream程交换到您的程序中,而无需更改使用它们的对象。 媒体播放器可能知道如何播放CD,MP3和WAV文件。 当然,你不想将这些回放algorithm硬编码到播放器中, 这将使添加像AVI这样的新格式变得困难。 此外,你的代码将被无用的case语句散布。 为了增加伤害,每次添加新algorithm时都需要更新这些案例。 总而言之,这不是一个非常面向对象的编程方式。
使用策略模式,您可以简单地将algorithm封装在对象后面。 如果你这样做,你可以随时提供新的媒体插件。 我们来调用插件类MediaStrategy。 该对象将有一个方法:playStream(Stream s)。 所以要添加一个新的algorithm,我们只需扩展我们的algorithm类。 现在,当节目遇到新的媒体types时,它只是将播放stream委托给我们的媒体策略。 当然,你需要一些pipe道来正确实例化你将需要的algorithm策略。
这是一个使用界面的好地方。 我们已经使用了战略模式,这清楚地表明devise中的一个地方将会改变。 因此,您应该将策略定义为一个接口。 当你想要一个对象具有某种types时,你通常应该使用接口来inheritanceinheritance。 在这种情况下,MediaStrategy。 依靠types身份的inheritance是危险的; 它将您locking到特定的inheritance层次结构中。 Java不允许多重inheritance,所以你不能扩展给你一个有用的实现或者更多的types标识。
另外请记住不要在面向对象( 请参见博客 )中被扫除,并且总是基于所需的行为build模对象,如果您正在devise一个应用程序,而您所需的唯一行为是动物的通用名称和物种,那么您只需要一个类动物与名字的财产,而不是世界上每一个可能的动物数以百万计的类。
接口应该很小。 真的很小。 如果你真的打破了你的对象,那么你的接口可能只包含一些非常具体的方法和属性。
抽象类是捷径。 是否有一些PetBase的衍生产品可以共享,您可以编写一次并完成? 如果是,那么抽象类是时候了。
抽象类也是有限的。 虽然它们给你一个生成子对象的捷径,但任何给定的对象只能实现一个抽象类。 很多时候,我发现这是一个抽象类的限制,这就是为什么我使用大量的接口。
抽象类可能包含几个接口。 你的PetBase抽象类可以实现IPet(宠物有所有者)和消化不良(宠物吃,或者至less他们应该)。 但是,PetBase可能不会实现IMammal,因为并不是所有的宠物都是哺乳动物,并不是所有的哺乳动物都是宠物。 您可以添加一个扩展PetBase并添加IMammal的MammalPetBase。 FishBase可以有PetBase并添加IFish。 IFish将ISwim和IUnderwaterBreather作为接口。
是的,我的示例对于这个简单的例子来说是非常复杂的,但这是关于接口和抽象类如何协同工作的重要组成部分。
我有一个粗略的经验法则
function性:可能在所有部分不同:界面。
数据和function,部分将大体相同,部分不同:抽象类。
数据和function,实际上工作,如果扩展只有轻微的变化:普通(具体)类
数据和function,没有改变计划:普通(具体)类与最终修改。
数据,也许是function:只读:枚举成员。
这是非常粗糙和准备就绪,并没有严格定义,但是有一个接口的频谱,一切都打算改为枚举,一切都固定有点像一个只读文件。
接口基类的情况在Submain .NET编码指南中得到了很好的解释:
基类与接口接口types是一个值的部分描述,可能受到许多对象types的支持。 尽可能使用基类而不是接口。 从版本angular度来看,类比接口更灵活。 有了课程,你可以运送版本1.0,然后在2.0版本中添加一个新的方法。 只要该方法不是抽象的,任何现有的派生类继续保持不变。
因为接口不支持实现inheritance,所以适用于类的模式不适用于接口。 向接口添加一个方法相当于将一个抽象方法添加到基类; 任何实现接口的类都会因为类没有实现新方法而中断。 在下列情况下接口是合适的:
- 几个不相关的类想要支持该协议。
- 这些类已经build立了基类(例如,一些是用户界面(UI)控件,一些是XML Web服务)。
- 聚合不合适或不切实际。 在所有其他情况下,类inheritance是一个更好的模型。
一个重要的区别是,你只能inheritance一个基类,但你可以实现很多接口。 所以你只想使用一个基类,如果你完全确定你不需要inheritance一个不同的基类。 另外,如果你发现你的界面变得越来越大,那么你应该开始把它分解成几个逻辑块来定义独立的function,因为没有规则说你的类不能全部实现(或者你可以定义一个不同的接口,只是inheritance他们都分组他们)。
当我第一次开始学习面向对象编程时,我发现了使用inheritance来共享常见行为的一个简单而可能是常见的错误 – 即使这种行为对于对象的本质来说不是必不可less的。
为了进一步build立一个在这个特定问题中被广泛使用的例子,有许多东西是可以被宠物的 – 女朋友,汽车,模糊的毛毯… – 所以我可能有一个Petable类提供了这个共同的行为,并且各种类inheritance从中。
然而,宠物并不属于任何这些物体的性质。 有很多更重要的概念,对他们的本性至关重要 – 女朋友是一个人,汽车是陆地车辆,猫是哺乳动物。
行为应该首先分配给接口(包括类的默认接口),并且只有当它们是(a)对于一大类是大类的子集的通用类时才被提升为基类, “猫”和“人”是“哺乳动物”的子集。
当你理解面向对象的devise之后,比起刚开始的时候就明白得多,你通常会自动地做这个,甚至不用考虑它。 所以,“代码到一个接口而不是一个抽象类”这个陈述的真实性就变得如此明显,你很难相信任何人都会这样说,并开始尝试去阅读其他的含义。
另一件我要补充的是,如果一个类纯粹是抽象的 – 没有非抽象的,非inheritance的成员或方法暴露给孩子,父母或客户端,那么为什么它是一个类? 它可以被replace,在某些情况下可以被接口替代,在其他情况下可以被replace为空。
以前有关使用抽象类进行通用实现的评论肯定是标志。 我还没有提到的一个好处是使用接口使得为了unit testing的目的而实现模拟对象变得更加容易。 如Jason Cohen所描述的,定义IPet和PetBase使您能够轻松地模拟不同的数据条件,而不需要物理数据库的开销(直到您决定是时候testing实际的东西了)。
除非你知道它是什么意思,否则不要使用基类,并且在这种情况下适用。 如果适用,则使用它,否则使用接口。 但请注意小接口的答案。
公共inheritance在OOD中过度使用,比大多数开发者意识到或愿意做到的要多得多。 参见Liskov可replace性原则
简而言之,如果A“是”B,那么对于每一种暴露的方法,A都要求不超过B,并且不得less于B.
从概念上讲,接口用于正式和半正式地定义对象将提供的一组方法。 Formally means a set of method names and signatures, semi-formally means human readable documentation associated with those methods. Interfaces are only descriptions of an API (after all, API stands for Application Programmer Interface ), they can't contain any implementation, and it's not possible to use or run an Interface. They only make explicit the contract of how you should interact with an object.
Classes provide an implementation, they can declare that they implement zero, one or more Interfaces. If a Class is intended to be inherited, the convention is to prefix the Class name with "Base".
There is a distinction between a Base Class and an Abstract Base Classes (ABC). ABCs mix interface and implementation together. Abstract outside of computer programming means "summary", that is "Abstract == Interface". An Abstract Base Class can then describe both an interface, as well as an empty, partial or complete implementation that is intended to be inherited.
Opinions on when to use Interfaces versus Abstract Base Classes versus just Classes is going to vary wildly based on both what you are developing, and which language you are developing in. Interfaces are often associated only with statically typed languages such as Java or C#, but dynamically typed languages can also have Interfaces and Abstract Base Classes. In Python for example, the distinction is made clear between a Class, which declares that it implements an Interface, and an object, which is an instance of a Class, and is said to provide that Interface. It's possible in a dynamic language that two objects that are both instances of the same Class, can declare that they provide completely different interfaces. In Python this is only possible for object attributes, while methods are shared state between all objects of a Class. However in Ruby, objects can have per-instance methods, so it's possible that the Interface between two objects of the same Class can vary as much as the programmer desires (however, Ruby doesn't have any explicit way of declaring Interfaces).
In dynamic languages the Interface to an object is often implicitly assumed, either by introspecting an object and asking it what methods it provides (Look Before You Leap) or preferably by simply attempting to use the desired Interface on an object and catching exceptions if the object doesn't provide that Interface (Easier to Ask Forgiveness than Permission). This can lead to "false positives" where two Interfaces have the same method name but are semantically different, however the trade-off is that your code is more flexible since you don't need to over specify up-front to anticipate all possible uses of your code.
Another option to keep in mind is using the "has-a" relationship, aka "is implemented in terms of" or "composition." Sometimes this is a cleaner, more flexible way to structure things than using "is-a" inheritance.
It may not make as much sense logically to say that Dog and Cat both "have" a Pet, but it avoids common multiple inheritance pitfalls:
public class Pet { void Bathe(); void Train(Trick t); } public class Dog { private Pet pet; public void Bathe() { pet.Bathe(); } public void Train(Trick t) { pet.Train(t); } } public class Cat { private Pet pet; public void Bathe() { pet.Bathe(); } public void Train(Trick t) { pet.Train(t); } }
Yes, this example shows that there is a lot of code duplication and lack of elegance involved in doing things this way. But one should also appreciate that this helps to keep Dog and Cat decoupled from the Pet class (in that Dog and Cat do not have access to the private members of Pet), and it leaves room for Dog and Cat to inherit from something else–possibly the Mammal class.
Composition is preferable when no private access is required and you don't need to refer to Dog and Cat using generic Pet references/pointers. Interfaces give you that generic reference capability and can help cut down on the verbosity of your code, but they can also obfuscate things when they are poorly organized. Inheritance is useful when you need private member access, and in using it you are committing yourself to highly coupling your Dog and Cat classes to your Pet class, which is a steep cost to pay.
Between inheritance, composition, and interfaces there is no one way that is always right, and it helps to consider how all three options can be used in harmony. Of the three, inheritance is typically the option that should be used the least often.
Prefer interfaces over abstract classes
Rationale, the main points to consider [two already mentioned here] are :
- Interfaces are more flexible, because a class can implement multiple interfaces. Since Java does not have multiple inheritance, using abstract classes prevents your users from using any other class hierarchy. In general, prefer interfaces when there are no default implementations or state. Java collections offer good examples of this (Map, Set, etc.).
- Abstract classes have the advantage of allowing better forward compatibility. Once clients use an interface, you cannot change it; if they use an abstract class, you can still add behavior without breaking existing code. If compatibility is a concern, consider using abstract classes.
- Even if you do have default implementations or internal state, consider offering an interface and an abstract implementation of it . This will assist clients, but still allow them greater freedom if desired [1].
Of course, the subject has been discussed at length elsewhere [2,3].
[1] It adds more code, of course, but if brevity is your primary concern, you probably should have avoided Java in the first place!
[2] Joshua Bloch, Effective Java, items 16-18.
It depends on your requirements. If IPet is simple enough, I would prefer to implement that. Otherwise, if PetBase implements a ton of functionality you don't want to duplicate, then have at it.
The downside to implementing a base class is the requirement to override
(or new
) existing methods. This makes them virtual methods which means you have to be careful about how you use the object instance.
Lastly, the single inheritance of .NET kills me. A naive example: Say you're making a user control, so you inherit UserControl
. But, now you're locked out of also inheriting PetBase
. This forces you to reorganize, such as to make a PetBase
class member, instead.
@Joel: Some languages (eg, C++) allow multiple-inheritance.
I usually don't implement either until I need one. I favor interfaces over abstract classes because that gives a little more flexibility. If there's common behavior in some of the inheriting classes I move that up and make an abstract base class. I don't see the need for both, since they essentially server the same purpose, and having both is a bad code smell (imho) that the solution has been over-engineered.
Regarding C#, in some senses interfaces and abstract classes can be interchangeable. However, the differences are: i) interfaces cannot implement code; ii) because of this, interfaces cannot call further up the stack to subclass; and iii) only can abstract class may be inherited on a class, whereas multiple interfaces may be implemented on a class.
Source : http://jasonroell.com/2014/12/09/interfaces-vs-abstract-classes-what-should-you-use/
C# is a wonderful language that has matured and evolved over the last 14 years. This is great for us developers because a mature language provides us with a plethora of language features that are at our disposal.
However, with much power becomes much responsibility. Some of these features can be misused, or sometimes it is hard to understand why you would choose to use one feature over another. Over the years, a feature that I have seen many developers struggle with is when to choose to use an interface or to choose to use an abstract class. Both have there advantages and disadvantages and the correct time and place to use each. But how to we decide???
Both provide for reuse of common functionality between types. The most obvious difference right away is that interfaces provide no implementation for their functionality whereas abstract classes allow you to implement some “base” or “default” behavior and then have the ability to “override” this default behavior with the classes derived types if necessary.
This is all well and good and provides for great reuse of code and adheres to the DRY (Don't Repeat Yourself) principle of software development. Abstract classes are great to use when you have an “is a” relationship.
For example: A golden retriever “is a” type of dog. So is a poodle. They both can bark, as all dogs can. However, you might want to state that the poodle park is significantly different than the “default” dog bark. Therefor, it could make sense for you to implement something as follows:
public abstract class Dog { public virtual void Bark() { Console.WriteLine("Base Class implementation of Bark"); } } public class GoldenRetriever : Dog { // the Bark method is inherited from the Dog class } public class Poodle : Dog { // here we are overriding the base functionality of Bark with our new implementation // specific to the Poodle class public override void Bark() { Console.WriteLine("Poodle's implementation of Bark"); } } // Add a list of dogs to a collection and call the bark method. void Main() { var poodle = new Poodle(); var goldenRetriever = new GoldenRetriever(); var dogs = new List<Dog>(); dogs.Add(poodle); dogs.Add(goldenRetriever); foreach (var dog in dogs) { dog.Bark(); } } // Output will be: // Poodle's implementation of Bark // Base Class implementation of Bark //
As you can see, this would be a great way to keep your code DRY and allow for the base class implementation be called when any of the types can just rely on the default Bark instead of a special case implementation. The classes like GoldenRetriever, Boxer, Lab could all could inherit the “default” (bass class) Bark at no charge just because they implement the Dog abstract class.
But I'm sure you already knew that.
You are here because you want to understand why you might want to choose an interface over an abstract class or vice versa. Well one reason you may want to choose an interface over an abstract class is when you don't have or want to prevent a default implementation. This is usually because the types that are implementing the interface not related in an “is a” relationship. Actually, they don't have to be related at all except for the fact that each type “is able” or has “the ablity” to do something or have something.
Now what the heck does that mean? Well, for example: A human is not a duck…and a duck is not a human. Pretty obvious. However, both a duck and a human have “the ability” to swim (given that the human passed his swimming lessons in 1st grade 🙂 ). Also, since a duck is not a human or vice versa, this is not an “is a” realationship, but instead an “is able” relationship and we can use an interface to illustrate that:
// Create ISwimable interface public interface ISwimable { public void Swim(); } // Have Human implement ISwimable Interface public class Human : ISwimable public void Swim() { //Human's implementation of Swim Console.WriteLine("I'm a human swimming!"); } // Have Duck implement ISwimable interface public class Duck: ISwimable { public void Swim() { // Duck's implementation of Swim Console.WriteLine("Quack! Quack! I'm a Duck swimming!") } } //Now they can both be used in places where you just need an object that has the ability "to swim" public void ShowHowYouSwim(ISwimable somethingThatCanSwim) { somethingThatCanSwim.Swim(); } public void Main() { var human = new Human(); var duck = new Duck(); var listOfThingsThatCanSwim = new List<ISwimable>(); listOfThingsThatCanSwim.Add(duck); listOfThingsThatCanSwim.Add(human); foreach (var something in listOfThingsThatCanSwim) { ShowHowYouSwim(something); } } // So at runtime the correct implementation of something.Swim() will be called // Output: // Quack! Quack! I'm a Duck swimming! // I'm a human swimming!
Using interfaces like the code above will allow you to pass an object into a method that “is able” to do something. The code doesn't care how it does it…All it knows is that it can call the Swim method on that object and that object will know which behavior take at run-time based on its type.
Once again, this helps your code stay DRY so that you would not have to write multiple methods that are calling the object to preform the same core function (ShowHowHumanSwims(human), ShowHowDuckSwims(duck), etc.)
Using an interface here allows the calling methods to not have to worry about what type is which or how the behavior is implemented. It just knows that given the interface, each object will have to have implemented the Swim method so it is safe to call it in its own code and allow the behavior of the Swim method be handled within its own class.
概要:
So my main rule of thumb is use an abstract class when you want to implement a “default” functionality for a class hierarchy or/and the classes or types you are working with share a “is a” relationship (ex. poodle “is a” type of dog).
On the other hand use an interface when you do not have an “is a” relationship but have types that share “the ability” to do something or have something (ex. Duck “is not” a human. However, duck and human share “the ability” to swim).
Another difference to note between abstract classes and interfaces is that a class can implement one to many interfaces but a class can only inherit from ONE abstract class (or any class for that matter). Yes, you can nest classes and have an inheritance hierarchy (which many programs do and should have) but you cannot inherit two classes in one derived class definition (this rule applies to C#. In some other languages you are able to do this, usually only because of the lack of interfaces in these languages).
Also remember when using interfaces to adhere to the Interface Segregation Principle (ISP). ISP states that no client should be forced to depend on methods it does not use. For this reason interfaces should be focused on specific tasks and are usually very small (ex. IDisposable, IComparable ).
Another tip is if you are developing small, concise bits of functionality, use interfaces. If you are designing large functional units, use an abstract class.
Hope this clears things up for some people!
Also if you can think of any better examples or want to point something out, please do so in the comments below!
An inheritor of a base class should have an "is a" relationship. Interface represents An "implements a" relationship. So only use a base class when your inheritors will maintain the is a relationship.
Use Interfaces to enforce a contract ACROSS families of unrelated classes. For example, you might have common access methods for classes that represent collections, but contain radically different data ie one class might represent a result set from a query, while the other might represent the images in a gallery. Also, you can implement multiple interfaces, thus allowing you to blend (and signify) the capabilities of the class.
Use Inheritance when the classes bear a common relationship and therefore have a similair structural and behavioural signature, ie Car, Motorbike, Truck and SUV are all types of road vehicle that might contain a number of wheels, a top speed
By def, interface provides a layer to communicate with other code. All the public properties and methods of a class are by default implementing implicit interface. We can also define an interface as a role, when ever any class needs to play that role, it has to implement it giving it different forms of implementation depending on the class implementing it. Hence when you talk about interface, you are talking about polymorphism and when you are talking about base class, you are talking about inheritance. Two concepts of oops !!!