我最近接受过两次电话采访,我被问及接口和抽象类之间的区别 . 我已经解释了我能想到的每一个方面,但似乎他们在等我提一些具体的东西,我不知道它是什么 .
根据我的经验,我认为以下是正确的 . 如果我错过了重点,请告诉我 .
Interface:
在接口中声明的每个单独的方法都必须在子类中实现 . 接口中只能存在事件,代理,属性(C#)和方法 . 一个类可以实现多个接口 .
Abstract Class:
只有抽象方法必须由子类实现 . Abstract类可以有实现的常规方法 . Abstract类还可以在Events,Delegates,Properties和Methods旁边有类变量 . 由于C#中不存在多重继承,因此类只能实现一个抽象类 .
-
毕竟,面试官想出了一个问题“如果你的抽象类只有抽象方法怎么办?那么它与界面会有什么不同?”我不知道答案,但我认为这是上面提到的继承权吗?
-
另一位采访者问我,如果你在界面中有一个Public变量,那么它与Abstract Class有什么不同?我坚持认为你不能在界面中有一个公共变量 . 我不知道他想听到什么,但他也不满意 .
See Also :
30 回答
其他差异:
抽象类可以有静态方法,属性,字段等,而运算符,接口则不能 . Cast运算符允许对抽象类进行强制转换,但不允许对接口进行强制转换 .
因此,即使它从未实现(通过其静态成员),您也可以自己使用抽象类,并且您不能以任何方式单独使用接口 .
回答第二个问题:
interface
中定义的public
变量默认为static final
,而abstract
类中的public
变量是实例变量 .Docs清楚地说,如果抽象类只包含抽象方法声明,则应将其声明为接口 .
接口中的变量默认为public static和final . 如果抽象类中的所有变量都是公共的,那么问题就可以构成一个框架?好吧,与接口中的变量不同,它们仍然可以是非静态的,非最终的 .
最后,我还要为上面提到的那些添加一点 - 抽象类仍然是类,并且属于单个继承树,而接口可以存在于多重继承中 .
我认为他们不喜欢你的回答,因为你给出了技术差异而不是设计差异 . 这个问题对我来说就像一个巨魔问题 . 事实上,接口和抽象类具有完全不同的性质,因此您无法真正比较它们 . 我将向您展示我对接口的作用是什么以及抽象类的作用是什么 .
interface: 用于确保 Contract 并在类之间 Build 低耦合,以便具有更易维护,可伸缩和可测试的应用程序 .
abstract class: 仅用于对具有相同责任性的类之间的某些代码进行分解 . 请注意,这是多重继承在OOP中是一件坏事的主要原因,因为class shouldn't handle many responsabilities(使用composition代替) .
因此,接口具有真正的架构角色,而抽象类几乎只是实现的细节(如果你当然正确使用它) .
从编码角度来看
如果抽象类只有抽象方法,那么接口可以替换抽象类 . 否则,将Abstract类更改为接口意味着您将失去继承提供的代码可重用性 .
从设计角度
如果它是“是一种”关系并且您需要子集或所有功能,请将其保留为抽象类 . 如果它是“应该做”关系,请将其保留为接口 .
确定您需要的内容:仅执行策略或代码可重用性和政策 .
由Jeffrey Richter通过C#复制CLR ......
我经常听到这样一个问题,“我应该设计一个基本类型还是一个界面?”答案并不总是明确的 .
以下是一些可能对您有所帮助的准则:
■■IS-A与CAN-DO关系类型只能继承一个实现 . 如果派生类型不能声明与基类型的IS-A关系,则不要使用基类型;使用界面 . 接口意味着CAN-DO关系 . 如果CAN-DO功能似乎属于各种对象类型,请使用接口 . 例如,类型可以将自身的实例转换为另一种类型(IConvertible),类型可以序列化自身的实例(ISerializable)等 . 请注意,值类型必须从System.ValueType派生,因此,它们不能派生来自任意基类 . 在这种情况下,您必须使用CAN-DO关系并定义接口 .
易于使用作为开发人员,通常更容易定义从基类型派生的新类型,而不是实现接口的所有方法 . 基类型可以提供许多功能,因此派生类型可能只需要对其行为进行相对较小的修改 . 如果提供接口,则新类型必须实现所有成员 .
■■一致的实施无论接口 Contract 的记录情况如何,每个人都不太可能100%正确地实施 Contract . 实际上,COM遇到了这个问题,这就是为什么有些COM对象只能与Microsoft Word或Windows Internet Explorer一起正常工作的原因 . 通过提供具有良好默认实现的基类型,您可以开始使用有效且经过充分测试的类型;然后,您可以修改需要修改的部件 .
■■版本控制如果向基类型添加方法,派生类型将继承新方法,您可以使用有效的类型开始,甚至不必重新编译用户的源代码 . 向接口添加新成员会强制接口的继承者更改其源代码并重新编译 .
采访者正在咆哮着一棵奇怪的树 . 对于像C#和Java这样的语言,有区别,但在其他方面像C这样的语言没有 . OO理论并没有区分这两者,只是语言的语法 .
抽象类是一个具有将继承的实现和接口(纯虚方法)的类 . 接口通常没有任何实现,只有纯虚函数 .
在C#或Java中,没有任何实现的抽象类与仅从用于从其继承的语法的接口不同,并且事实上您只能从一个继承 .
1)一个接口可以看作是一个纯粹的抽象类,是相同的,但尽管如此,实现一个接口并从一个抽象类继承是不一样的 . 当你从这个纯抽象类继承时,你定义了一个层次结构 - >继承,如果你实现了你不是的接口,你可以实现任意数量的接口,但是你只能从一个类继承 .
2)您可以在接口中定义属性,因此实现该接口的类必须具有该属性 .
例如:
实现该接口的类必须具有类似的属性 .
我认为他们正在寻找的答案是基本或OPPS的哲学差异 .
当派生类共享抽象类的核心属性和行为时,将使用抽象类继承 . 实际定义类的行为 .
另一方面,当类共享外围行为时,使用接口继承,而不必定义派生类 .
例如 . 汽车和卡车共享汽车抽象类的许多核心属性和行为,但他们也分享一些外围行为,如生成排气,甚至非汽车类如钻孔机或PowerGenerators共享,并不一定定义汽车或卡车,所以Car,Truck,Driller和PowerGenerator都可以共享IExhaust相同的界面 .
Inheritance
考虑一辆汽车和一辆公共汽车 . 它们是两种不同的载体 . 但是,他们仍然有一些共同的特性,比如他们有转向,刹车,齿轮,发动机等 .
因此,使用继承概念,这可以表示如下......
现在一辆自行车......
还有一辆车......
这就是继承 . 我们使用它们将对象分类为更简单的Base形式及其子代,如上所述 .
Abstract Classes
抽象类是不完整的对象 . 为了进一步理解,让我们再次考虑车辆类比 .
可以驾驶车辆 . 对?但是不同的车辆以不同的方式驾驶......例如,驾驶自行车时不能驾驶汽车 .
那么如何表示车辆的驱动功能呢?更难以检查它是什么类型的车辆并用它自己的功能驱动它;添加新型车辆时,您必须反复更改Driver类 .
这里有抽象类和方法的作用 . 您可以将驱动器方法定义为抽象,以告知每个继承子项必须实现此功能 .
所以,如果你修改车辆类......
自行车和汽车还必须指定如何驾驶它 . 否则,代码将无法编译并引发错误 .
简而言之,抽象类是一个部分不完整的类,其中包含一些不完整的函数,继承的子函数必须指定它们自己的函数 .
Interfaces 接口完全不完整 . 他们没有任何 property . 他们只是表明继承的孩子能够做某事......
假设您有不同类型的手机 . 他们每个人都有不同的方式来做不同的功能;例如:打电话给一个人 . 手机制造商指定了如何做到这一点 . 在这里,手机可以拨打一个号码 - 也就是说,它是可拨号的 . 让我们将其表示为一个界面 .
这里Dialable的制造商定义了如何拨号 . 您只需要拨打一个号码即可拨号 .
因此使用接口而不是抽象类,使用Dialable的函数的编写者不必担心它的属性 . 例如:它是否有触摸屏或拨号盘,是固定固定电话还是手机 . 你只需要知道它是否可以录音;它是否继承(或实现)Dialable接口 .
更重要的是,如果有一天你用不同的方式切换Dialable
您可以确定代码仍然可以正常工作,因为使用dialable的函数不会(也不能)依赖于Dialable接口中指定的细节以外的细节 . 它们都实现了Dialable接口,这是函数唯一关心的 .
开发人员通常使用接口来确保对象之间的互操作性(可互换使用),只要它们共享一个共同的功能(就像您可能更改为固定电话或移动电话一样,只需要拨打一个号码) . 简而言之,接口是一个更简单的抽象类版本,没有任何属性 .
另外,请注意你可以实现(继承)任意数量的接口,但您只能扩展(继承)单个父类 .
More Info Abstract classes vs Interfaces
Interface:-
== contract . 无论哪个类实现它都必须遵循所有接口规范 .一个实时的例子是任何
ISO
标记的产品 .ISO
给出了关于如何构建产品的rules/specification
以及minimum set of features
它Must
的内容 .这只是
subset of properties
产品必须有.ISO将签署产品only if it satisfies the its standards
.现在看看这段代码
这里
Fastrack
被称为 Watch ,因为it has all that features that a watch must suppost
( Minimum set of features ) .Why and When Abstract:
From MSDN:
abstract class
的目的是提供多个派生类可以共享的common definition of a base class
.例如,类库可以定义一个抽象类,该抽象类用作许多函数的参数,并要求程序员使用该库通过创建派生类来提供自己的类实现 .
Abstract simply means if you cannot define it completely declare it as an abstract
. 实现类将完成此实现 .例如:假设我将一个类
Recipe
声明为抽象,但我不知道要制作哪个配方 . 然后我将推广这个类以定义common definition of any recipe
. implantation of recipe will depend on implementing dish.抽象类可以包含抽象方法,也可以不抽象方法 . 因此,您可以注意到Interface中的差异 . 不一定是实现类必须具有的每个方法 . 您只需要覆盖抽象方法 .
简单的话如果你想
tight coupling use Interface o/w use in case of lose coupling Abstract Class
大多数答案都集中在抽象类和接口之间的技术差异,但从技术上讲,接口基本上是一种抽象类(一个没有任何数据或实现),我认为 conceptual 差异更有趣,这可能是什么面试官都在追求 .
Interface 是 agreement . 它指定:"this is how we're going to talk to each other" . 它可以't have any implementation because it'不应该有任何实现 . 它's a contract. It'就像C中的
.h
头文件一样 .Abstract Class 是 incomplete implementation . 类可能实现也可能不实现接口,而抽象类不必完全实现它 . 没有任何实现的抽象类是没用的,但完全合法 .
基本上任何类(抽象与否)都是关于它的内容,而接口则是关于如何使用它 . 例如:
Animal
可能是一个抽象类,实现了一些基本的代谢功能,并指定了呼吸和运动的抽象方法而没有给出实现,因为它不知道它是应该通过鳃还是肺呼吸,以及它是否飞行,游泳,走路或爬行 . 另一方面,Mount
可能是一个界面,它指定你可以骑动物,而不知道它是什么类型的动物(或者它是否是动物!) .幕后的事实,一个接口基本上是一个只有抽象方法的抽象类,并不重要 . 从概念上讲,他们完全扮演不同的角色 .
简短:抽象类用于 Modelling 类似外观类的类层次结构(例如,Animal可以是抽象类,Human,Lion,Tiger可以是具体的派生类)
和
接口用于 Communication 之间的2个相似/不相似的类,它们不关心实现接口的类的类型(例如,Height可以是接口属性,它可以由Human,Building,Tree实现 . 如果你能吃的话也没关系,你可以游泳,你可以死或任何东西..重要的只是你需要有高度(在你的课堂实施)) .
还有其他一些差异 -
接口不能具有任何具体实现 . 抽象基类可以 . 这允许您在那里提供具体的实现 . 这可以允许抽象基类实际提供更严格的 Contract ,而界面实际上只描述了如何使用类 . (抽象基类可以具有定义行为的非虚拟成员,从而为基类作者提供更多控制 . )
可以在类上实现多个接口 . 类只能从单个抽象基类派生 . 这允许使用接口的多态层次结构,但不允许抽象基类 . 这也允许使用接口进行伪多继承 .
可以在v2中修改抽象基类,而不会破坏API . 对接口的更改正在发生变化 .
[C#/ .NET特定]接口与抽象基类不同,可以应用于值类型(结构) . 结构不能从抽象基类继承 . 这允许行为 Contract /使用指南应用于值类型 .
从another answer of mine开始,主要是处理何时使用一个与另一个:
怎么样比喻:当我在空军时,我去了飞行员训练,并成为美国空军(美国空军)的飞行员 . 那时我没有资格飞行任何东西,不得不参加飞机型训练 . 一旦我获得资格,我就是一名飞行员(抽象班)和一名C-141飞行员(具体 class ) . 在我的一项任务中,我获得了额外职责:安全官 . 现在我仍然是一名飞行员和一名C-141飞行员,但我也履行了安全官职责(我实施了ISafetyOfficer,可以这么说) . 一名飞行员不需要担任安全官,其他人也可以这样做 .
所有美国空军飞行员都必须遵守某些空军规定,所有C-141(或F-16或T-38)飞行员都是'美国空军飞行员' . 任何人都可以成为安全官 . 所以,总结一下:
Pilot:抽象类
C-141飞行员:具体课程
ISafety官员:界面
补充说明:这是一个类比,以帮助解释概念,而不是编码建议 . 请参阅下面的各种评论,讨论很有意思 .
从概念上讲,通过使用任何一个或两个来保持语言特定的实现,规则,好处和实现任何编程目标,可以或不能拥有代码/数据/属性,等等,单个或多个继承,全部放在一边
1-抽象(或纯抽象)类旨在实现层次结构 . 如果您的业务对象在结构上看起来有点类似,那么只表示父子(层次结构)类关系,那么将使用继承/抽象类 . 如果您的业务模型没有层次结构,则不应使用继承(这里我不是在讨论编程逻辑,例如某些设计模式需要继承) . 从概念上讲,抽象类是一种在OOP中实现业务模型层次结构的方法,它与Interfaces无关,实际上将Abstract类与Interface进行比较是没有意义的,因为两者在概念上完全不同,在访谈中只是要检查概念,因为它看起来在实现时都提供了相同的功能,我们程序员通常更多地强调编码 . [请记住,抽象与抽象类不同] .
2-接口是一种 Contract ,是由一组或多组功能代表的完整业务功能 . 这就是为什么它被实现而不是继承 . 业务对象(层次结构的一部分)可以具有任意数量的完整业务功能 . 它与抽象类无关,一般意味着继承 . 例如,人类可以运行,大象可以运行,鸟可以运行,等等,所有这些不同层次的对象都将实现RUN接口或EAT或SPEAK接口 . 不要进入实现,因为您可能将其实现为具有实现这些接口的每种类型的抽象类 . 任何层次结构的对象都可以具有与其层次结构无关的功能(接口) .
我相信,Interfaces并不是为了实现多重继承或暴露公共行为而发明的,类似地,纯抽象类不是否决于接口,但是Interface是一个对象可以做的功能(通过该接口的功能),而Abstract Class代表一个要生成的层次结构的父级具有父级核心结构(属性功能)的子级
当您被问及差异时,除非明确询问,否则实际上概念差异不是特定于语言的实现的差异 .
我相信,两位采访者都期待这两者之间存在直线上的差异,当你失败时,他们试图通过实施ONE作为其他方式来驱使你走向这种差异 .
通过实现接口,您实现了组合(“has-a”关系)而不是继承(“is-a”关系) . 这是一个重要的原则要记住,当涉及到设计模式之类的东西时,你需要使用接口来实现行为的组合而不是继承 .
虽然这个问题已经很老了,但我想补充一点赞成接口:
可以使用任何依赖注入工具注入接口,而极少数支持抽象类注入 .
我将解释接口和抽象类的深度细节 . 如果你知道关于接口和抽象类的概述,那么当我们应该使用接口和何时应该使用抽象类时,第一个问题会出现在你的脑海中 . 所以请查看以下接口和抽象类的说明 .
如果你不了解实现,我们有需求规范,那么我们选择Interface
如果您知道实现但不完全(部分实现),那么我们使用Abstract类 .
Interface
默认情况下每个方法的公共抽象意味着接口是100%纯抽象的 .
Abstract
可以有Concrete方法和Abstract方法,什么是具体方法,在Abstract类中有实现,抽象类是一个被声明为abstract的类 - 它可能包含也可能不包含抽象方法 .
Interface
我们不能将接口声明为私有,受保护
问:为什么我们不声明接口是私有的和受保护的?
因为默认情况下接口方法是公共抽象,所以我们没有将接口声明为私有和受保护的原因 .
Interface method
我们也不能将接口声明为private,protected,final,static,synchronized,native .....
我将给出原因:为什么我们不声明同步方法,因为我们不能创建接口的对象和同步是对象的工作所以和儿子的原因我们没有声明同步方法瞬态概念也不适用因为瞬态工作与同步 .
Abstract
我们很高兴地使用公共的,私人的最终静态....意味着没有限制适用于抽象 .
Interface
变量在接口中声明为默认的public static final,因此我们也不会声明变量为private,protected .
易失性修饰符也不适用于接口,因为接口变量默认为public static final和final变量,一旦将值赋值给变量就无法更改值,一旦将变量声明为接口,就必须分配变量 .
而且变量是变化的,所以它是对手 . 最终这就是我们不在界面中使用volatile变量的原因 .
Abstract
抽象变量无需声明public static final .
我希望这篇文章很有用 .
界面:
我们没有实现(或定义)方法,我们在派生类中这样做 .
我们不在接口中声明成员变量 .
接口表示HAS-A关系 . 这意味着它们是物体的掩模 .
抽象类:
我们可以在抽象类中声明和定义方法 .
我们隐藏它的构造函数 . 这意味着没有直接从它创建的对象 .
抽象类可以保存成员变量 .
派生类继承到抽象类,表示派生类中的对象未被屏蔽,它继承到抽象类 . 在这种情况下的关系是IS-A .
这是我的意见 .
如果您将
java
视为OOP语言来回答此问题,那么Java 8版本会使上述答案中的某些内容过时 . 现在java接口可以有默认方法和具体实现 .Oracle website提供了
interface
和abstract
类之间的主要区别 .Consider using abstract classes 如果:
您想在几个密切相关的类之间共享代码 .
您希望扩展抽象类的类具有许多常用方法或字段,或者需要除公共之外的访问修饰符(例如protected和private) .
您想声明非静态或非最终字段 .
Consider using interfaces 如果:
您希望不相关的类实现您的接口 . 例如,许多不相关的对象可以实现
Serializable
接口 .您希望指定特定数据类型的行为,但不关心谁实现其行为 .
你想要多重继承类型的优点 .
简单来说,我想用
interface: 通过多个不相关的对象实现 Contract
abstract class: 在多个相关对象之间实现相同或不同的行为
看看代码示例,以清楚的方式理解事物:How should I have explained the difference between an Interface and an Abstract class?
虽然你的问题表明它是“普通的OO”,但它似乎真正关注.NET对这些术语的使用 .
在.NET中(类似于Java):
接口可以没有状态或实现
实现接口的类必须提供该接口的所有方法的实现
抽象类可能包含state(数据成员)和/或实现(方法)
抽象类可以在不实现抽象方法的情况下继承(尽管这样的派生类本身就是抽象的)
接口可能是多重继承的,抽象类可能不是(这可能是接口与abtract类分开存在的关键具体原因 - 它们允许实现多重继承,从而消除了一般MI的许多问题) .
作为一般的OO术语,差异不一定是明确定义的 . 例如,有些C程序员可能拥有类似的严格定义(接口是不能包含实现的抽象类的严格子集),而有些人可能会说具有一些默认实现的抽象类仍然是一个接口或非抽象的class仍然可以定义一个接口 .
实际上,有一个称为非虚拟接口(NVI)的C语言,其中公共方法是非虚拟方法,可以“窃取”私有虚拟方法:
http://www.gotw.ca/publications/mill18.htm
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface
由于您可能从专家那里获得了理论知识,我在这里重复所有这些并没有花太多的话,而是让我用一个简单的例子来解释我们可以使用/不能使用
Interface
和Abstract class
.考虑一下您正在设计一个列出Cars的所有功能的应用程序 . 在各个方面,你需要共同的继承,因为一些属性,如DigitalFuelMeter,Air Conditioning,Seat adjustment等,对于所有汽车来说都很常见 . 同样,我们只需要某些类的继承,因为制动系统(ABS,EBD)等一些属性仅适用于某些汽车 .
以下类充当所有汽车的基类:
考虑我们为每辆车分别设一个 class .
考虑我们需要一种方法来继承Verna和Cruze汽车的制动技术(不适用于Alto) . 虽然两者都使用制动技术,但“技术”却不同 . 所以我们正在创建一个抽象类,其中方法将被声明为Abstract,它应该在其子类中实现 .
现在我们试图继承这个抽象类,并且在Verna和Cruze中实现了制动系统的类型:
看到上面两个类的问题?它们继承自C#.Net不允许的多个类,即使该方法是在子代中实现的 . 这就是Interface的需要 .
实现如下:
现在Verna和Cruze可以在Interface的帮助下通过自己的制动技术实现多重继承 .
当然,了解OOP中接口和抽象类的行为(以及语言如何处理它们)非常重要,但我认为理解每个术语的含义也很重要 . 你能想象
if
命令与术语的含义完全不同吗?而且,实际上有些语言正在减少,甚至更多,界面和抽象之间的差异...如果有一天这两个术语几乎完全相同,至少你可以定义自己应该在哪里(以及为什么)应该是用于 .如果您阅读了一些字典和其他字体,您可能会发现同一术语有不同的含义,但有一些共同的定义 . 我认为我在_107422中找到的这两个含义真的非常非常适合 .
接口:
抽象:
例:
你买了一辆车,它需要燃料 .
你的车型是
XYZ
,属于类型ABC
,所以它是一辆混凝土车,一辆汽车的特定实例 . 汽车不是真正的物体 . 实际上,它是创建特定对象的一组抽象标准(质量) . 简而言之,汽车是一个 abstract class ,它是“一种集中于任何更广泛或更普遍的基本品质的东西” .应该使用唯一符合汽车手册规格的燃料来填充汽车油箱 . 实际上,没有什么可以限制你投入任何燃料,但发动机只能正常工作指定的燃料,所以最好遵循其要求 . 要求说,它接受同样类型的其他汽车
ABC
,一套标准的燃料 .在面向对象的视图中,不应将类型
ABC
的燃料声明为类,因为那里没有特定类型汽车的混凝土燃料 . 虽然您的汽车可以接受抽象级燃料或车辆燃料,但您必须记住,您现有的唯一车辆燃料符合规格,那些符合您汽车手册要求的规格 . 简而言之,他们应该实现 interfaceABCGenreFuel
,“......使单独的,有时不兼容的元素能够有效协调” .附录
另外,我认为你应该记住术语类的含义,它是(来自前面提到的同一站点):
类:
这样,类(或抽象类)不应仅表示公共属性(如接口),而应表示具有公共属性的某种组 . 接口不需要代表一种 . 它必须代表共同的属性 . 这样,我认为类和抽象类可以用来表示不应该经常改变其方面的东西,比如人类是哺乳动物,因为它代表了某种类型 . 种类不应该经常改变自己 .
对于.Net,
你对第二个面试官的回答也是第一个面试的答案......抽象类可以有实现,AND状态,接口不能......
编辑:另一方面,我甚至不会使用短语'subclass'(或'继承'短语)来描述“定义为实现”接口的类 . 对我来说,接口是一个 Contract 的定义,如果一个类被定义为“实现”该接口,那么该类必须符合该 Contract . 它不会继承任何东西......你必须自己明确添加所有内容 .
接口是执行特定行为的轻量级方式 . 这是一种思考方式 .
Interface Types vs. Abstract Base Classes
改编自Pro C# 5.0 and the .NET 4.5 Framework书 .
接口类型可能看起来与抽象基类非常相似 . 回想一下,当一个类被标记为抽象时,它可以定义任意数量的抽象成员,以便为所有派生类型提供多态接口 . 但是,即使类确实定义了一组抽象成员,也可以自由定义任意数量的构造函数,字段数据,非抽象成员(带实现)等 . 另一方面,接口仅包含抽象成员定义 . 由抽象父类 Build 的多态接口受到一个主要限制,因为只有派生类型支持抽象父类定义的成员 . 但是,在较大的软件系统中,开发多个类层次结构是非常常见的,这些层次结构除了System.Object之外没有共同的父级 . 鉴于抽象基类中的抽象成员仅适用于派生类型,我们无法在不同层次结构中配置类型以支持相同的多态接口 . 举例来说,假设您已定义以下抽象类:
根据此定义,只有扩展CloneableType的成员才能支持Clone()方法 . 如果您创建一组不扩展此基类的新类,则无法获得此多态接口 . 此外,您可能还记得C#不支持类的多重继承 . 因此,如果您想创建一个CarVan并且是CloneableType的MiniVan,则无法执行此操作:
正如您所猜测的,接口类型可以解决 . 定义接口后,它可以由任何类或结构,任何层次结构,任何命名空间或任何程序集(用任何.NET编程语言编写)实现 . 如您所见,接口具有高度多态性 . 考虑在System命名空间中定义的名为ICloneable的标准.NET接口 . 此接口定义了一个名为Clone()的方法:
接口定义服务或服务集的 Contract . 它们以水平方式提供多态性,因为两个完全不相关的类可以实现相同的接口,但可以互换地用作它们实现的接口类型的参数,因为这两个类都承诺满足接口定义的服务集 . 接口不提供实现细节 .
抽象类为其子库定义基本结构,并可选择部分实现 . 抽象类以垂直但有方向的方式提供多态性,因为任何继承抽象类的类都可以被视为该抽象类的实例,而不是相反 . 抽象类可以并且经常包含实现细节,但不能自己实例化 - 只有它们的子类可以“新建” .
C#的确如此请注意,允许接口继承 .
Interface :如果您想对可能相互关联或不相关的组件施加规则,则应使用
Pros:
允许多重继承
通过不暴露上下文中正在使用的确切类型的对象来提供抽象
通过 Contract 的特定签名提供一致性
Cons:
必须实施所有定义的 Contract
不能有变量或委托
一旦定义了,就不能在不破坏所有类的情况下进行更改
Abstract Class :应该用于您希望对彼此相关的组件具有某些基本或默认行为或实现的位置
Pros:
比界面更快
具有实施的灵活性(您可以全部或部分实施)
可以在不破坏派生类的情况下轻松更改
Cons:
无法实例化
不支持多重继承