Hou*_*man 1372 oop abstract-class interface
我最近接受过两次电话采访,其中我被问及接口和抽象类之间的区别.我已经解释了他能想到的每一个方面,但似乎他们在等我提一些具体的东西,我不知道它是什么.
根据我的经验,我认为以下是正确的.如果我错过了重点,请告诉我.
接口:
在接口中声明的每个单独的方法都必须在子类中实现.接口中只能存在事件,代理,属性(C#)和方法.一个类可以实现多个接口.
抽象类:
只有抽象方法必须由子类实现.Abstract类可以有实现的常规方法.Abstract类还可以在Events,Delegates,Properties和Methods旁边有类变量.由于C#中不存在多重继承,因此类只能实现一个抽象类.
毕竟,面试官想出了一个问题"如果你有一个只有抽象方法的抽象类怎么办?那么它与界面会有什么不同?" 我不知道答案,但我认为这是上面提到的继承权吗?
另一位采访者问我,如果你在界面中有一个Public变量,那么它与Abstract Class有什么不同?我坚持认为你不能在界面中有一个公共变量.我不知道他想听到什么,但他也不满意.
另见:
Jay*_*Jay 843
怎么样比喻:当我在空军时,我去了飞行员训练,并成为美国空军(美国空军)的飞行员.那时我没有资格飞行任何东西,不得不参加飞机类训练.一旦我获得资格,我就是一名飞行员(抽象班)和一名C-141飞行员(具体班级).在我的一项任务中,我获得了额外的职责:安全官.现在我仍然是一名飞行员和一名C-141飞行员,但我也履行了安全官职责(我实施了ISafetyOfficer,可以这么说).一名飞行员不需要担任安全官员,其他人也可以这样做.
所有美国空军飞行员都必须遵守某些空军规定,所有C-141(或F-16或T-38)飞行员都是'美国空军飞行员'.任何人都可以成为安全官.所以,总结一下:
补充说明:这是一个类比,以帮助解释概念,而不是编码建议.请参阅下面的各种评论,讨论很有意思.
Mic*_*urr 722
虽然你的问题表明它是"普通OO",但它似乎真正关注.NET对这些术语的使用.
在.NET中(类似于Java):
作为一般的OO术语,差异不一定是明确的.例如,有些C++程序员可能持有类似的严格定义(接口是不能包含实现的抽象类的严格子集),而有些人可能会说具有一些默认实现的抽象类仍然是一个接口或非抽象的class仍然可以定义一个接口.
实际上,有一种称为非虚拟接口(NVI)的C++习惯用法,其中公共方法是非虚拟方法,可以"窃取"私有虚拟方法:
小智 216
我认为他们正在寻找的答案是基本或OPPS的哲学差异.
当派生类共享抽象类的核心属性和行为时,将使用抽象类继承.实际定义类的行为.
另一方面,当类共享外围行为时,使用接口继承,而不必定义派生类.
例如.一辆汽车和一辆卡车分享了很多核心属性和汽车抽象类的行为,但他们也分享一些外围行为像生成废气甚至非汽车类,如钻孔机或PowerGenerators份额,并不一定限定汽车或卡车,所以Car,Truck,Driller和PowerGenerator都可以共享IExhaust相同的界面.
Dha*_*jay 193
简短:抽象类用于建模类似外观类的类层次结构(例如,Animal可以是抽象类,而Human,Lion,Tiger可以是具体的派生类)
和
接口用于2个相似/不相似的类之间的通信,它们不关心实现接口的类的类型(例如,Height可以是接口属性,它可以由Human,Building,Tree实现.如果你可以吃就没关系,你可以游泳,你可以死或任何东西..重要的只是你需要有高度(在你的课堂实施)).
Ree*_*sey 77
还有其他一些差异 -
接口不能有任何具体的实现.抽象基类可以.这允许您在那里提供具体的实现.这可以允许抽象基类实际提供更严格的契约,而界面实际上只描述了如何使用类.(抽象基类可以具有定义行为的非虚拟成员,从而为基类作者提供更多控制.)
可以在类上实现多个接口.类只能从单个抽象基类派生.这允许使用接口的多态层次结构,但不允许抽象基类.这也允许使用接口进行伪多重继承.
可以在v2 +中修改抽象基类,而不会破坏API.对接口的更改正在破坏更改.
[C#/ .NET特定]接口与抽象基类不同,可以应用于值类型(结构).结构不能从抽象基类继承.这允许行为合同/使用指南应用于值类型.
fz_*_*lam 67
继承
考虑一辆汽车和一辆公共汽车.它们是两种不同的载体.但是,他们仍然有一些共同的属性,比如他们有转向,刹车,齿轮,引擎等.
所以继承概念,这可以表示如下......
public class Vehicle {
private Driver driver;
private Seat[] seatArray; //In java and most of the Object Oriented Programming(OOP) languages, square brackets are used to denote arrays(Collections).
//You can define as many properties as you want here ...
}
Run Code Online (Sandbox Code Playgroud)
现在是自行车......
public class Bicycle extends Vehicle {
//You define properties which are unique to bicycles here ...
private Pedal pedal;
}
Run Code Online (Sandbox Code Playgroud)
还有一辆车......
public class Car extends Vehicle {
private Engine engine;
private Door[] doors;
}
Run Code Online (Sandbox Code Playgroud)
这就是继承.我们使用它们将对象分类为更简单的Base形式及其子代,如上所示.
抽象类
抽象类是不完整的对象.为了进一步理解,让我们再次考虑车辆类比.
可以驾驶车辆.对?但是不同的车辆以不同的方式驾驶......例如,你驾驶自行车时不能驾驶汽车.
那么如何表示车辆的驱动功能呢?更难以检查它是什么类型的车辆并用它自己的功能驱动它; 添加新型车辆时,您必须反复更改Driver类.
这里有抽象类和方法的作用.您可以将驱动器方法定义为抽象,以告知每个继承子项必须实现此函数.
所以,如果你修改车辆类......
//......Code of Vehicle Class
abstract public void drive();
//.....Code continues
Run Code Online (Sandbox Code Playgroud)
自行车和汽车还必须指定如何驾驶它.否则,代码将无法编译并引发错误.
简而言之,抽象类是一个部分不完整的类,其中包含一些不完整的函数,继承的子函数必须指定它们自己的函数.
接口
接口完全不完整.他们没有任何财产.他们只是表明继承的孩子能够做某事......
假设你有不同类型的手机.他们每个人都有不同的方式来做不同的功能; 例如:打电话给一个人.手机制造商指定了如何做到这一点.在这里,手机可以拨打一个号码 - 也就是说,它是可拨号的.让我们将其表示为一个界面.
public interface Dialable {
public void dial(Number n);
}
Run Code Online (Sandbox Code Playgroud)
这里Dialable的制造商定义了如何拨打号码.您只需要拨打一个号码即可拨号.
// Makers define how exactly dialable work inside.
Dialable PHONE1 = new Dialable() {
public void dial(Number n) {
//Do the phone1's own way to dial a number
}
}
Dialable PHONE2 = new Dialable() {
public void dial(Number n) {
//Do the phone2's own way to dial a number
}
}
//Suppose there is a function written by someone else, which expects a Dialable
......
public static void main(String[] args) {
Dialable myDialable = SomeLibrary.PHONE1;
SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....
Run Code Online (Sandbox Code Playgroud)
因此使用接口而不是抽象类,使用Dialable的函数的编写者不必担心它的属性.例如:它是否有触摸屏或拨号盘,是固定固定电话还是手机.你只需要知道它是否可以被拨打; 它是否继承(或实现)Dialable接口.
更重要的是,如果有一天你用不同的方式切换Dialable
......
public static void main(String[] args) {
Dialable myDialable = SomeLibrary.PHONE2; // <-- changed from PHONE1 to PHONE2
SomeOtherLibrary.doSomethingUsingADialable(myDialable);
}
.....
Run Code Online (Sandbox Code Playgroud)
您可以确定代码仍然可以正常工作,因为使用dialable的函数不会(也不能)依赖于Dialable接口中指定的细节以外的细节.它们都实现了Dialable接口,这是函数唯一关心的东西.
开发人员通常使用接口来确保对象之间的互操作性(可互换使用),只要它们共享一个共同的功能(就像您可能更改为固定电话或移动电话一样,只需要拨打一个号码).简而言之,接口是一个更简单的抽象类版本,没有任何属性.
另请注意,您可以根据需要实现(继承)任意数量的接口,但您只能扩展(继承)单个父类.
更多信息 抽象类与接口
Rav*_*abu 40
如果您考虑java使用OOP语言来回答这个问题,那么Java 8版本会使上述答案中的某些内容过时.现在java接口可以有默认方法和具体实现.
Oracle 网站提供了类interface和abstract类之间的主要区别.
考虑使用抽象类,如果:
考虑使用接口:
Serializable接口.简单来说,我想用
interface:通过多个不相关的对象实现合同
抽象类:在多个相关对象之间实现相同或不同的行为
看看代码示例以清楚的方式理解事物:我应该如何解释Interface和Abstract类之间的区别?
Ste*_*owe 32
采访者正在咆哮着一棵奇怪的树.对于像C#和Java这样的语言,有区别,但在其他语言中,如C++则没有.OO理论并没有区分这两者,仅仅是语言的语法.
抽象类是一个包含将继承的实现和接口(纯虚方法)的类.接口通常没有任何实现,只有纯虚函数.
在C#或Java中,没有任何实现的抽象类与仅从用于从其继承的语法的接口不同,并且事实上您只能从一个继承.
The*_*TXI 31
通过实现接口,您实现了组合("has-a"关系)而不是继承("is-a"关系).这是一个重要的原则,要记住在涉及设计模式的事情时,您需要使用接口来实现行为的组合而不是继承.
bja*_*jan 26
从概念上讲,通过使用任何一个或两个来保持语言特定的实现,规则,好处和实现任何编程目标,可以或不能拥有代码/数据/属性,等等,单个或多个继承,全部放在一边
1-抽象(或纯抽象)类旨在实现层次结构.如果您的业务对象在结构上看起来有点相似,那么只表示父子(层次结构)类关系,那么将使用继承/抽象类.如果您的业务模型没有层次结构,则不应使用继承(这里我不是在讨论编程逻辑,例如某些设计模式需要继承).从概念上讲,抽象类是一种在OOP中实现业务模型层次结构的方法,它与Interfaces无关,实际上将Abstract类与Interface进行比较是没有意义的,因为两者在概念上完全不同,在访谈中只是要检查概念因为它看起来在实现时都提供了相同的功能,我们程序员通常更多地强调编码.[请记住,抽象与抽象类不同].
2-接口是合同,是由一组或多组功能表示的完整业务功能.这就是为什么它被实现而不是继承.业务对象(层次结构的一部分或非层次结构)可以具有任意数量的完整业务功能.它与抽象类无关,一般意味着继承.例如,人类可以运行,大象可以运行,鸟可以运行,等等,所有这些不同层次的对象都将实现RUN接口或EAT或SPEAK接口.不要进入实现,因为您可能将其实现为具有实现这些接口的每种类型的抽象类.任何层次结构的对象都可以具有与其层次结构无关的功能(接口).
我相信,Interfaces并不是为了实现多重继承或暴露公共行为而发明的,类似地,纯抽象类不是否决于接口,而Interface是一个对象可以做的功能(通过该接口的功能)和Abstract Class代表一个生成具有父级核心结构(属性+功能)的子级的层次结构的父级
当您被问及差异时,除非明确询问,否则实际上是概念差异而不是语言特定实现的差异.
我相信,两位采访者都期待这两者之间存在直线上的差异,当你失败时,他们试图通过实施ONE作为其他方式来驱使你走向这种差异.
如果你有一个只有抽象方法的Abstract类怎么办?
Jeg*_*ala 26
我将解释接口和抽象类的深度细节.如果您了解接口和抽象类的概述,那么当我们应该使用接口时以及何时应该使用抽象类时,第一个问题会出现在您的脑海中.所以请查看以下接口和抽象类的说明.
什么时候应该使用Interface?
如果你不了解实现只是我们有需求规范,那么我们使用Interface
什么时候应该使用抽象类?
如果您知道实现但不完全(部分实现),那么我们使用Abstract类.
接口
默认情况下,每个方法的公共抽象意味着接口是100%纯抽象.
抽象
可以有Concrete方法和抽象方法,什么是具体方法,在Abstract类中有实现,抽象类是一个被声明为abstract的类 - 它可能包含也可能不包含抽象方法.
接口
我们不能将接口声明为私有,受保护
问:为什么我们不声明接口是私有的和受保护的?
因为默认情况下接口方法是公共抽象,所以我们没有声明接口是私有的和受保护的.
接口方法
我们也不能声明接口为private,protected,final,static,synchronized,native .....
我将给出原因:为什么我们不声明同步方法,因为我们不能创建接口的对象和同步是对象的工作所以和儿子的原因我们没有声明同步方法瞬态概念也不适用因为瞬态工作与同步.
抽象
我们很高兴地使用公共的,私人的最终静态....意味着没有限制适用于抽象.
接口
变量在接口中声明为默认的公共静态final,因此我们也不会将变量声明为private,protected.
易失性修饰符也不适用于接口,因为接口变量默认为public static final和final变量,一旦将值赋值给变量就不能更改值,一旦将变量声明为接口,就必须分配变量.
而且变量是变化的,所以它就是对手.最终这就是我们不在界面中使用volatile变量的原因.
抽象
抽象变量不需要声明public static final.
我希望这篇文章很有用.
Cha*_*ana 21
对于.Net,
你对第二个面试官的回答也是对第一个面试者的答案......抽象类可以有实现,AND状态,接口不能......
编辑:另一方面,我甚至不会使用短语"子类"(或"继承"短语)来描述"定义为实现"接口的类.对我来说,接口是一个合同的定义,如果一个类被定义为"实现"该接口,那么该类必须符合该合同.它不会继承任何东西......你必须自己添加一切,明确地.
K.M*_*iao 19
这些答案都太长了。
接口用于定义行为。
抽象类用于定义事物本身,包括其行为。这就是为什么我们有时会创建一个带有一些继承接口的额外属性的抽象类。
这也解释了为什么 Java 只支持类的单继承,而对接口没有限制。因为一个具体的对象不能是不同的东西,但它可以有不同的行为。
bou*_*ter 18
接口:如果您想要对可能相互关联或不相关的组件施加规则,则应使用此接口
优点:
缺点:
抽象类:应该用于您希望对彼此相关的组件具有某些基本或默认行为或实现的位置
优点:
缺点:
Gnu*_*cki 17
我认为他们不喜欢你的回答,因为你给出了技术差异而不是设计差异.这个问题对我来说就像一个巨魔问题.事实上,接口和抽象类具有完全不同的性质,因此您无法真正比较它们.我将向您展示我对接口的作用是什么以及抽象类的作用是什么.
interface:用于确保合同并在类之间建立低耦合,以便具有更易维护,可伸缩和可测试的应用程序.
abstract class:仅用于对具有相同责任性的类之间的某些代码进行分解.请注意,这是多重继承在OOP中是一件坏事的主要原因,因为类不应该处理许多响应(而是使用组合).
所以接口具有真正的架构角色,而抽象类几乎只是实现的细节(如果你当然正确使用它).
Ani*_*kur 13
After all that, the interviewer came up with the question "What if you had an
Abstract class with only abstract methods? How would that be different
from an interface?"
Run Code Online (Sandbox Code Playgroud)
文档明确指出,如果抽象类只包含抽象方法声明,则应将其声明为接口.
An another interviewer asked me what if you had a Public variable inside
the interface, how would that be different than in Abstract Class?
Run Code Online (Sandbox Code Playgroud)
接口中的变量默认为public static和final.如果抽象类中的所有变量都是公共的,那么问题就可以被设置为框架?好吧,与接口中的变量不同,它们仍然可以是非静态的,非最终的.
最后,我要再添加一点上面提到的那些 - 抽象类仍然是类并且属于单个继承树,而接口可以存在于多个继承中.
nau*_*svn 12
这是我的意见.
Dee*_*hra 12
由Jeffrey Richter通过C#复制CLR ......
我经常听到这样一个问题,"我应该设计一个基本类型还是一个界面?"答案并不总是明确的.
以下是一些可能对您有所帮助的准则:
■■IS-A与CAN-DO关系类型只能继承一个实现.如果派生类型不能声明与基类型的IS-A关系,则不要使用基类型; 使用界面.接口意味着CAN-DO关系.如果CAN-DO功能似乎属于各种对象类型,请使用接口.例如,类型可以将自身的实例转换为另一种类型(IConvertible),类型可以序列化自身的实例(ISerializable)等.请注意,值类型必须从System.ValueType派生,因此,它们不能派生来自任意基类.在这种情况下,您必须使用CAN-DO关系并定义接口.
易于使用作为开发人员,您通常更容易定义从基本类型派生的新类型,而不是实现接口的所有方法.基类型可以提供许多功能,因此派生类型可能只需要对其行为进行相对较小的修改.如果提供接口,则新类型必须实现所有成员.
■■一致的实施无论接口合同的记录情况如何,每个人都不太可能100%正确地实施合同.事实上,COM遇到了这个问题,这就是为什么有些COM对象只能与Microsoft Word或Windows Internet Explorer一起正常工作的原因.通过提供具有良好默认实现的基类型,您可以开始使用有效且经过充分测试的类型; 然后,您可以修改需要修改的部件.
■■版本控制如果向基类型添加方法,派生类型将继承新方法,则首先使用有效的类型,甚至不必重新编译用户的源代码.向接口添加新成员会强制接口的继承者更改其源代码并重新编译.
joe*_*dev 10
接口定义服务或服务集的合同.它们以水平方式提供多态性,因为两个完全不相关的类可以实现相同的接口,但可以互换地用作它们实现的接口类型的参数,因为这两个类都承诺满足接口定义的服务集.接口不提供实现细节.
抽象类为其子阶段定义基础结构,并可选择部分实现.抽象类以垂直但有方向的方式提供多态性,因为任何继承抽象类的类都可以被视为该抽象类的实例,而不是相反.抽象类可以并且经常包含实现细节,但不能自己实例化 - 只有它们的子类可以"新建".
C#确实允许接口继承,请注意.
mcv*_*mcv 10
大多数答案都集中在抽象类和接口之间的技术差异,但从技术上讲,接口基本上是一种抽象类(一个没有任何数据或实现),我认为概念差异更有趣,这可能是什么面试官都在追求.
一个接口是一个协议.它规定:"这就是我们如何相互交谈".它不能有任何实现,因为它不应该有任何实现.这是一份合同.它就像.hC中的头文件.
一个抽象类是一个不完整的实现.类可能实现也可能不实现接口,而抽象类不必完全实现它.没有任何实现的抽象类是没用的,但完全合法.
基本上任何类,抽象与否,都是关于它是什么,而接口是关于你如何使用它.例如:Animal可能是一个实现一些基本代谢功能的抽象类,并指定用于呼吸和运动的抽象方法而不给出实施,因为它不知道它是应该通过鳃或肺呼吸,以及它是否飞行,游泳,散步或爬.Mount另一方面,可能是一个界面,它指明你可以骑动物,而不知道它是什么类型的动物(或者它是否是动物!).
在幕后,接口基本上是一个只有抽象方法的抽象类这一事实并不重要.从概念上讲,他们完全扮演不同的角色.
Sar*_*avu 10
正如你可能已经得到了有关专家的理论知识,我不是在这里重复所有那些花很多话,而让我用一个简单的例子,我们可以使用/不能使用说明Interface和Abstract class.
考虑一下您正在设计一个列出Cars的所有功能的应用程序.在各个方面,您需要共同继承,因为DigitalFuelMeter,Air Conditioning,Seat adjustment等一些属性对于所有汽车来说都很常见.同样,我们只需要某些类的继承,因为制动系统(ABS,EBD)等一些属性仅适用于某些汽车.
以下类充当所有汽车的基类:
public class Cars
{
public string DigitalFuelMeter()
{
return "I have DigitalFuelMeter";
}
public string AirCondition()
{
return "I have AC";
}
public string SeatAdjust()
{
return "I can Adjust seat";
}
}
Run Code Online (Sandbox Code Playgroud)
考虑我们为每辆车都有一个单独的课程.
public class Alto : Cars
{
// Have all the features of Car class
}
public class Verna : Cars
{
// Have all the features of Car class + Car need to inherit ABS as the Braking technology feature which is not in Cars
}
public class Cruze : Cars
{
// Have all the features of Car class + Car need to inherit EBD as the Braking technology feature which is not in Cars
}
Run Code Online (Sandbox Code Playgroud)
考虑一下我们需要一种方法来继承Verna和Cruze汽车的制动技术(不适用于Alto).虽然两者都使用制动技术,但"技术"却不同.所以我们创建了一个抽象类,其中方法将被声明为Abstract,它应该在其子类中实现.
public abstract class Brake
{
public abstract string GetBrakeTechnology();
}
Run Code Online (Sandbox Code Playgroud)
现在我们试图继承这个抽象类,并且在Verna和Cruze中实现了制动系统的类型:
public class Verna : Cars,Brake
{
public override string GetBrakeTechnology()
{
return "I use ABS system for braking";
}
}
public class Cruze : Cars,Brake
{
public override string GetBrakeTechnology()
{
return "I use EBD system for braking";
}
}
Run Code Online (Sandbox Code Playgroud)
看到上面两个类的问题?它们继承自C#.Net不允许的多个类,即使该方法是在子代中实现的.这就是接口的需要.
interface IBrakeTechnology
{
string GetBrakeTechnology();
}
Run Code Online (Sandbox Code Playgroud)
实现如下:
public class Verna : Cars, IBrakeTechnology
{
public string GetBrakeTechnology()
{
return "I use ABS system for braking";
}
}
public class Cruze : Cars, IBrakeTechnology
{
public string GetBrakeTechnology()
{
return "I use EBD system for braking";
}
}
Run Code Online (Sandbox Code Playgroud)
现在Verna和Cruze可以在Interface的帮助下通过自己的制动技术实现多重继承.
1)一个接口可以看作是纯粹的抽象类,是相同的,但尽管如此,实现一个接口并从一个抽象类继承是不一样的.当你从这个纯抽象类继承时,你定义了一个层次结构 - >继承,如果你实现了你不是的接口,你可以实现任意数量的接口,但是你只能从一个类继承.
2)您可以在接口中定义属性,因此实现该接口的类必须具有该属性.
例如:
public interface IVariable
{
string name {get; set;}
}
Run Code Online (Sandbox Code Playgroud)
实现该接口的类必须具有类似的属性.
接口类型与抽象基类
改编自Pro C#5.0和.NET 4.5 Framework书.
接口类型可能看起来非常类似于抽象基类.回想一下,当一个类被标记为抽象时,它可以定义任意数量的抽象成员,以便为所有派生类型提供多态接口.但是,即使一个类确实定义了一组抽象成员,也可以自由定义任意数量的构造函数,字段数据,非抽象成员(带有实现)等等.另一方面,接口仅包含抽象成员定义.由抽象父类建立的多态接口受到一个主要限制,因为只有派生类型支持抽象父类定义的成员.但是,在较大的软件系统中,开发除System.Object之外没有共同父级的多个类层次结构是很常见的.鉴于抽象基类中的抽象成员仅适用于派生类型,我们无法在不同层次结构中配置类型以支持相同的多态接口.举例来说,假设您已定义以下抽象类:
public abstract class CloneableType
{
// Only derived types can support this
// "polymorphic interface." Classes in other
// hierarchies have no access to this abstract
// member.
public abstract object Clone();
}
Run Code Online (Sandbox Code Playgroud)
根据此定义,只有扩展CloneableType的成员才能支持Clone()方法.如果您创建一组不扩展此基类的新类,则无法获得此多态接口.此外,您可能还记得C#不支持类的多重继承.因此,如果您想创建一个CarVan并且是CloneableType的MiniVan,则无法执行此操作:
// Nope! Multiple inheritance is not possible in C#
// for classes.
public class MiniVan : Car, CloneableType
{
}
Run Code Online (Sandbox Code Playgroud)
正如您所猜测的那样,接口类型可以解决问题.定义接口后,它可以由任何类或结构,任何层次结构,任何命名空间或任何程序集(用任何.NET编程语言编写)实现.如您所见,接口具有高度多态性.考虑在System命名空间中定义的名为ICloneable的标准.NET接口.此接口定义了一个名为Clone()的方法:
public interface ICloneable
{
object Clone();
}
Run Code Online (Sandbox Code Playgroud)
当然,了解OOP中的接口和抽象类的行为(以及语言如何处理)很重要,但是我认为了解每个术语的确切含义也很重要。您能想象该if命令不能完全按照术语的含义工作吗?同样,实际上,某些语言正在减少甚至更大程度地减少了界面和抽象之间的差异……如果有一天偶然,这两个术语的操作几乎完全相同,至少您可以定义自己应该在哪里(以及为什么)定义它们用于。
如果您通读一些词典和其他字体,可能会发现同一术语具有不同的含义,但具有一些共同的定义。我认为我在本站点中发现的这两种含义非常非常好并且很合适。
接口:
一种事物或情况,可以使单独的,有时是不兼容的元素有效地进行协调。
抽象:
某种东西本身集中于任何更广泛或更普遍的东西或几件事的本质素质;本质。
例:
您买了一辆汽车,它需要燃料。
您的汽车模型为XYZ,属于类型ABC,因此它是混凝土汽车,是汽车的特定实例。汽车不是真正的物体。实际上,它是创建特定对象的一组抽象标准(质量)。简而言之,Car是一个抽象类,它是“某种东西本身就集中了任何更广泛或更普遍的东西的本质素质”。
只能使用符合汽车手册规格的燃料来填充汽车油箱。实际上,没有任何限制可以放任何燃料,但是发动机只能使用指定的燃料才能正常工作,因此最好遵循其要求。要求说,它接受与其他同类汽车一样ABC的标准燃料。
在面向对象的观点中,ABC不应将用于体裁的燃料声明为类别,因为那里没有用于特定类型汽车的混凝土燃料。尽管您的汽车可以接受抽象类的Fuel(燃料)或VehicularFuel(车辆燃料),但您必须记住,您现有的仅有部分车辆燃料符合规范,即满足您汽车手册中要求的规范。简而言之,他们应该实现接口 ABCGenreFuel,该接口“ ...使单独的,有时是不兼容的元素能够有效地进行协调”。
另外,我认为您应该牢记“类”一词的含义,即(来自前面提到的同一站点):
类:
由于共同的属性,特征,品质或特质而被视为一个团体的许多人或事物;类;
这样,一个类(或抽象类)不应仅表示公共属性(如接口),而应表示具有公共属性的某种组。接口不需要代表一种。它必须代表通用属性。这样,我认为类和抽象类可以用来表示不应该经常改变其外观的事物,例如人类哺乳动物,因为它代表了某些种类。种类不应该经常改变自己。
从编码的角度
如果抽象类只有抽象方法,则接口可以替换抽象类。否则,将抽象类更改为接口意味着您将失去继承提供的代码可重用性。
从设计角度
如果它是一个“是”关系并且您需要一个子集或所有功能,请将其保留为抽象类。如果它是“应该做”的关系,则将其保留为接口。
确定您需要什么:只是策略执行,或代码可重用性和策略。
tl;博士; 当您看到“是 A”关系时,请使用继承/抽象类。当您看到“具有”关系时,请创建成员变量。当您看到“依赖于外部提供者”时实现(而不是继承)一个接口。
面试题:接口和抽象类有什么区别?你如何决定何时使用什么?我大多得到以下一个或所有答案: 答案 1:您不能创建抽象类和接口的对象。
ZK(这是我的首字母缩写):您不能创建任何一个对象。所以这没有区别。这是接口和抽象类之间的相似之处。反问:为什么不能创建抽象类或接口的对象?
答案 2:抽象类可以有一个函数体作为部分/默认实现。
ZK:反问:所以如果我把它改成一个纯抽象类,把所有的虚函数都标记为抽象的,并且不为任何虚函数提供默认的实现。这会使抽象类和接口相同吗?之后它们可以互换使用吗?
答案 3:接口允许多重继承,而抽象类则不允许。
ZK:反问:你真的从接口继承吗?或者你只是实现一个接口并从抽象类继承?实现和继承有什么区别?这些反问问题让考生望而却步,让大多数人摸不着头脑,或者只是转到下一个问题。这让我认为人们需要有关面向对象编程的这些基本构建块的帮助。原始问题和所有反问题的答案都可以在英语和 UML 中找到。您必须至少了解以下内容才能更好地理解这两个结构。
普通名词:普通名词是对同一类或同类事物“共同”赋予的名称。例如水果、动物、城市、汽车等。
专有名词:专有名词是物体、地点或事物的名称。苹果、猫、纽约、本田雅阁等。
汽车是一个普通名词。本田雅阁是一个专有名词,可能是一个复合专有名词,一个由两个名词组成的专有名词。
来到 UML 部分。您应该熟悉以下关系:
让我们考虑以下两句话。- 本田雅阁是汽车吗?- 本田雅阁有车吗?
哪一个听起来是正确的?简单的英语和理解。HondaAccord 和 Cars 有着“Is A”的关系。本田雅阁里面没有汽车。这是辆车。本田雅阁“有一个”音乐播放器。
当两个实体共享“是 A”关系时,它更适合继承。并且具有关系是创建成员变量的更好候选者。有了这个,我们的代码看起来像这样:
abstract class Car
{
string color;
int speed;
}
class HondaAccord : Car
{
MusicPlayer musicPlayer;
}
Run Code Online (Sandbox Code Playgroud)
现在本田不生产音乐播放器。或者至少这不是他们的主要业务。
所以他们联系了其他公司并签订了合同。如果您在这里接收电源并且这两条线上的输出信号在这些扬声器上播放得很好。
这使得音乐播放器成为界面的完美候选者。只要连接工作正常,您并不关心谁为其提供支持。
您可以用 Sony 或其他方式替换 LG 的 MusicPlayer。它不会改变本田雅阁的任何事情。
为什么不能创建抽象类的对象?
因为你不能走进陈列室说给我一辆车。您必须提供专有名词。什么车?应该是本田雅阁。那时销售代理可以为您提供一些东西。
为什么不能创建接口的对象?因为你不能走进陈列室说给我一份音乐播放器的合同。它不会有帮助。消费者和提供者之间的接口只是为了促进达成协议。您将如何处理协议副本?它不会播放音乐。
为什么接口允许多重继承?
接口不是继承的。接口已实现。界面是与外部世界交互的候选者。本田雅阁有加油接口。它有给轮胎充气的接口。和用来给足球充气的软管是一样的。所以新代码如下所示:
abstract class Car
{
string color;
int speed;
}
class HondaAccord : Car, IInflateAir, IRefueling
{
MusicPlayer musicPlayer;
}
Run Code Online (Sandbox Code Playgroud)
而英文会这样读:“Honda Accord is a Car that support the 充气轮胎和加油”。
| 归档时间: |
|
| 查看次数: |
688651 次 |
| 最近记录: |