对于这些问题,这里有一些奇妙的答案,涉及关于接口和松耦合代码,控制反转等的各种详细信息。这里有一些相当令人头疼的讨论,所以我想借此机会分解一下内容,以了解界面为什么有用。
当我第一次接触接口时,我也对接口的相关性感到困惑。我不明白你为什么需要他们。如果我们正在使用Java或C#之类的语言,那么我们已经拥有继承,我将接口视为一种较弱的继承形式,并认为“为什么要打扰?” 从某种意义上说我是对的,您可以将接口视为一种较弱的继承形式,但除此之外,我最终通过将它们视为对由其表现出的常见特征或行为进行分类的一种手段,最终将它们用作语言构造。可能有许多不相关的对象类别。
例如,假设您有一个SIM卡游戏,并且具有以下课程:
class HouseFly inherits Insect {
void FlyAroundYourHead(){}
void LandOnThings(){}
}
class Telemarketer inherits Person {
void CallDuringDinner(){}
void ContinueTalkingWhenYouSayNo(){}
}
显然,就直接继承而言,这两个对象没有共同点。但是,您可以说它们都很烦人。
假设我们的游戏需要某种随机的东西,使玩家在吃晚餐时会感到烦恼。这可能是一个HouseFly或一个Telemarketer或两个-但你怎么允许对于用一个单一的功能?以及您如何要求每种不同类型的对象以相同的方式“做他们烦人的事情”?
要实现的关键是,尽管a Telemarketer和a HouseFly共享一个共同的松散解释的行为,即使它们在建模方面也不相同。因此,让我们创建一个可以实现的接口:
interface IPest {
void BeAnnoying();
}
class HouseFly inherits Insect implements IPest {
void FlyAroundYourHead(){}
void LandOnThings(){}
void BeAnnoying() {
FlyAroundYourHead();
LandOnThings();
}
}
class Telemarketer inherits Person implements IPest {
void CallDuringDinner(){}
void ContinueTalkingWhenYouSayNo(){}
void BeAnnoying() {
CallDuringDinner();
ContinueTalkingWhenYouSayNo();
}
}
现在,我们有两个类,每个类都可能以自己的方式令人讨厌。而且他们不需要从相同的基类派生出来并共享共同的固有特性-他们只需要满足合同IPest-合同就是简单的。你只需要BeAnnoying。在这方面,我们可以建立以下模型:
class DiningRoom {
DiningRoom(Person[] diningPeople, IPest[] pests) { ... }
void ServeDinner() {
when diningPeople are eating,
foreach pest in pests
pest.BeAnnoying();
}
}
在这里,我们有一间餐厅,可以容纳许多食客和许多害虫-请注意该界面的使用。这意味着在我们的小世界中,pests数组的成员实际上可能是一个Telemarketer对象或一个HouseFly对象。
该ServeDinner方法在晚餐时供我们使用,而我们在饭厅里的人应该就餐。在我们的小游戏中,这是我们的害虫执行其工作的时候-指示每种害虫通过IPest界面来烦人。这样,我们可以轻松地同时拥有这两种方式,Telemarketers并且HouseFlys以各自的方式烦人-我们只在乎我们在DiningRoom物体中有某种东西是有害生物,我们并不真正在乎它是什么,它们可能什么也没有与其他共同。
这个非常人为的伪代码示例(比我预期的拖了更长的时间)仅是为了说明最终使我了解何时使用接口的那种事情。对于该示例的愚蠢行为,我事先表示歉意,但希望它对您的理解有所帮助。而且,可以肯定的是,您在此处收到的其他已发布答案确实涵盖了当今在设计模式和开发方法中使用接口的范围。