可能重复:
When to use an interface instead of an abstract class and vice versa?
嗨,我正在向非程序员教授OOP概念。我想知道如何解释界面和抽象类之间的区别 我实际上正在寻找的是一个真实世界的例子,可以帮助突出两者之间的差异。
答案 0 :(得分:35)
在我的Java课程中,我经常使用这种类型的图像并询问:“这是什么?”
每次有人会说“那是一名球员”。从这张图片中你可以教任何人界面是什么。此接口允许任何用户“播放”某些内容。每个人都知道这些按钮的含义,即使你不知道将要做什么,你可以使用这个界面的任何东西,你知道小箭头将“播放”,其他箭头可能会向前或向后发送你。 所有具有这些按钮的内容都将提供任何用户在开始使用之前都会知道的标准行为。
我通常会尽量避免可能被误解的“契约”一词。
然后从Play界面,我转到录像机(或DVD)播放器。 DVD播放器的每个构造函数都必须添加一些特殊功能,以将简单的未知播放器转换为DVD播放器。例如弹出按钮。他们必须正确实施播放器 播放按钮将启动DVD的内容。
但即使DVD播放器提供DVD播放器的基本行为,也不是一切都已完成。你不能简单地拥有“一个”DVD播放器,它有一个品牌,大多数时候它有自己的固件。这次你需要扩展DVD播放器抽象类来添加你自己的小组件。
答案 1 :(得分:21)
这是两者的良好比较:interface vs abstract class。我从下面复制了一个具体的例子:
接口通常用于描述类的外围能力,而不是其中心身份,例如: Automobile类可以实现Recyclable接口,该接口可以应用于许多其他完全不相关的对象。
抽象类定义其后代的核心标识。如果你定义了一个狗抽象类,那么达尔马提亚的后代就是狗,他们不仅仅是可爱的。已实现的接口枚举了类可以执行的一般操作,而不是类的内容。
答案 2 :(得分:3)
<强>接口强>
界面只是一个规范。它描述了必须做的事情。没有更多,没有更少。就其本身而言,它毫无意义。只有当有人采用该规范并实现它时,它才有用。
想想USB记忆棒。它符合USB的规格。与它通信的设备不需要知道或关心记忆棒如何处理它的工作,它需要知道的是当我们要求写入数据时,它被写入;相反,当我们要求从中读取数据时,我们希望收到数据。
在计算方面,我们以相同的方式使用界面。如果我们有:
public interface IUSB
{
Data Read();
bool Write(Data data);
}
我们知道实现此接口的任何内容都必须提供Read和Write的实现。幕后的幕后操作与我们无关。通过在我们的代码周围传递一个接口,我们不会将自己与特定的实现联系起来。
抽象类
Abstract Class简单地为我们提供了一种方法,用于在派生类型必须实现的基类中放置规范,以及可以由所有派生类型使用的公共代码。
我一直在努力寻找一个很好的现实世界的例子并且一直在努力,所以只能真正想出一个代码示例。
假设您想在代码中实现员工层次结构。所以你可能有:
public abstract class Employee
{
public string FirstName { get; protected set; }
public string LastName { get; protected set; }
public string Grade { get; protected set; }
public int Salary { get; protected set; }
public abstract void GivePayRise();
}
每位员工都有一个姓名和相关的工作等级。我们可以使用前3个属性在基类中对此进行建模。但是,根据等级等,给予奖金可能不是一件简单的事情。因此,我们将其标记为抽象。每个派生类型的员工(兼职,全职,合同,顾问)都必须实现这一点。
实施可能是:
public class FullTimeEmployee : Employee
{
public void GivePayRise()
{
Salary *= 1.1;
}
}
public class PartTimeEmployee : Employee
{
public void GivePayRise()
{
Salary *= 1;
}
}
所以我们想给全职员工加薪10%,但不要兼职。
很难给出好的例子 - 我通常倾向于使用接口,在我使用抽象类时,在过去一年左右的时间里无法记住。这可以启动整个抽象类与接口的争论,但这是一个全新的页面.......
答案 3 :(得分:1)
对于计算机相关的一切,我使用烹饪晚餐的例子。我首先说硬盘是机柜/存储柜。记忆就像你的柜台。处理器是烹饪设备(炉子)。你就像系统总线(移动东西等等)。因此,当您启动计算机时,您将基本成分从存储中取出并将它们放在柜台上(加载操作系统)。这是一个松散的例子,但效果很好。
现在进入OOP:一种成分是一种物体,一种工具(碗,刀,勺等)也是如此。其中每一个都有属性(knife = handle_color:black,blade_type:serrated等...)。每个人都有你可以用它们执行的方法/动作(刀=切(辣椒))。
现在你可以随意拿走这个。例如,有绿色,黄色和红色辣椒。每一个都是辣椒,所以你可以说“继承辣椒类”(外行人:把你所知道的关于辣椒的一切都应用到这个特定的辣椒上,辣椒有颜色属性,红辣椒颜色=红色)。
你甚至可以将类与实例分开(这个特定的胡椒是一个实例,而在食谱卡上它是一个类)。
所以你可以制作一些伪代码:
class pepper {
var color
var spiciness
var size
}
class redPepper extends pepper {
construct(){
$this->color=red
}
}
class cuttingKnife extends knife{
construct(){
$this->blade_type=serated
}
}
class cookingPot extends pot{
construct(){
//We all know what a cooking pot is
}
}
class stove extends apparatus{
construct(){
//We all know what a stove is
}
}
$knife = new cuttingKnife();
$myPepper = new redPepper();
$pot = new cookingPot();
$stove = new stove();
$knife->cut($myPepper);
$pot->putOn($stove);
$stove->cookOn("high");
$pot->putIn("water");
$pot->putIn($myPepper);
//This will boil a cut pepper
当然,人们不一定了解伪代码,但他们会理解如何煮沸。他们会理解“辣椒”和“红辣椒”之间的区别。我认为你可以将这个类比用于任何与电脑相关的东西,只需要一些小小的推文。
等等...
答案 4 :(得分:1)
界面:遥控器的按钮。用户知道这些按钮应该如何运作。
具体课程:东芝RC,飞利浦RC,JVC RC - 内部框中的具体实现。
答案 5 :(得分:1)
抽象类:裁缝使用的模板,用于创建Made to measure garment。虽然你不能穿模板本身,它可以用来制作套装你可以穿 - 套装是从模板“衍生出来的”。
界面:dress code。
答案 6 :(得分:0)
一个很好的例子是计算器。计算器内部是一块电路板,它的显示屏,按钮和逻辑处理器之间有连接。
电路板就像一个抽象类。它为使用它构建的任何计算器提供管道。此外,它还具有连接到显示器,按钮阵列和逻辑处理器的某些接口。
反过来,任何与电路板一起工作的显示器必须具有适合电路板上显示器接口的连接器。按钮和逻辑处理器也是如此,后者可能具有与电路板上的接口对齐的特定引脚排列。
使用OOD的开发人员将创建一个抽象类CalculatorBase来定义按钮,显示和内部逻辑之间的管道。抽象类还将指定派生类如何使用此管道来响应某些事件。
然而,CalculatorBase不依赖于特定的显示,特定的按钮组,甚至逻辑的特定实现。相反,开发人员为每个接口指定一个接口,例如ICalculatorDisplay。 ICalculatorDisplay将指定CalculatorBase期望与显示交互的方式。然后,CalculatorBase将与任何实现ICalculatorDisplay的显示一起使用。
答案 7 :(得分:0)
(在某些语言中,抽象类的使用方式与接口相同,因此可能会令人困惑)
少数几个都有一定共同界面的类就像是一些可以填写句子空白的单词。例如:
然而,课程本身,虽然它们都可以在句子中填空,但两者之间没有任何关系。鸡是飞禽,空客A320是飞机。唯一的共同点是他们都有一些我们称之为“翅膀”的东西。 (你也可以说,在两种情况下,“翅膀”的真正含义是不同的。)
class IHasWings : public IUnknown
{
public:
// IUnknown methods: (Inherited)
// IHasWings methods:
virtual HRESULT GetWingSpan([out] double* pdblWingSpan) = 0;
virtual HRESULT IsWingMovable([out] BOOL* pIsMovable) = 0;
virtual HRESULT IsWingDetachable([out] BOOL* pIsDetachable) = 0;
};
class Chicken : public ... ..., public IHasWings
{
};
class AirbusA320 : public ... ..., public IHasWings
{
};
答案 8 :(得分:0)
非常简单地说,界面定义了你如何与我交谈。
而抽象课可以定义我的一个天赋,比如弹吉他。问题是“弹吉他”本身并没有那么有用。但我们可以利用这种能力来创造一种人,比如音乐家(我们可以说是一个阶级)。