面向对象编程中“接口”的定义是啥
Posted
技术标签:
【中文标题】面向对象编程中“接口”的定义是啥【英文标题】:What is the definition of "interface" in object oriented programming面向对象编程中“接口”的定义是什么 【发布时间】:2011-02-21 11:00:42 【问题描述】:好的,我的一个朋友来回讨论“接口”在编程中的含义。
“界面”的最佳描述是什么。
对我来说,接口是类的蓝图,这是最好的定义吗?
【问题讨论】:
不是骗子,但它为这个问题提供了很多启示:***.com/questions/444245/… 我会说这是一个通用词,但对我来说仍然意味着同样的事情。它就像一个特定或更抽象实体的墙,向外部提供一些输入点并在不了解内部操作的情况下给它们输出。我认为它可以被称为在 OOP 中定义从低到高级别的抽象。 【参考方案1】:在编程中,接口定义了对象将具有的行为,但实际上并没有指定行为。这是一个契约,它将保证某个类可以做某事。
在这里考虑这段 C# 代码:
using System;
public interface IGenerate
int Generate();
// Dependencies
public class KnownNumber : IGenerate
public int Generate()
return 5;
public class SecretNumber : IGenerate
public int Generate()
return new Random().Next(0, 10);
// What you care about
class Game
public Game(IGenerate generator)
Console.WriteLine(generator.Generate())
new Game(new SecretNumber());
new Game(new KnownNumber());
Game 类需要一个密码。为了测试它,您想注入将用作秘密数字的内容(此原理称为控制反转)。
游戏类希望对实际创建随机数的内容“持开放态度”,因此它将在其构造函数中询问“任何具有 Generate 方法的内容”。
首先,接口指定对象将提供哪些操作。它只包含它的外观,但没有给出实际的实现。这只是方法的签名。按照惯例,在 C# 中,接口以 I 为前缀。
这些类现在实现了 IGenerate 接口。这意味着编译器将确保它们都有一个方法,该方法返回一个 int 并称为 Generate
。
游戏现在被称为两个不同的对象,每个对象都实现了正确的接口。其他类在构建代码时会产生错误。
这里我注意到你使用的蓝图类比:
类通常被视为对象的蓝图。接口指定了一个类需要做的事情,所以有人可能会说它确实只是一个类的蓝图,但是由于一个类不一定需要一个接口,我认为这个比喻是有问题的。将接口视为合同。法律要求(由编译器警察强制执行)“签署”的类遵守合同中的条款和条件。这意味着它必须执行接口中指定的操作。
这完全是由于某些 OO 语言的静态类型特性,Java 或 C# 就是这种情况。另一方面,在 Python 中,使用了另一种机制:
import random
# Dependencies
class KnownNumber(object):
def generate(self):
return 5
class SecretNumber(object):
def generate(self):
return random.randint(0,10)
# What you care about
class SecretGame(object):
def __init__(self, number_generator):
number = number_generator.generate()
print number
在这里,没有一个类实现接口。 Python 并不关心这一点,因为SecretGame
类只会尝试调用传入的任何对象。如果对象有一个 generate() 方法,那么一切都很好。如果没有:卡普特!
这个错误不会在编译时出现,而是在运行时出现,因此可能在您的程序已经部署和运行时出现。 C# 会在您接近之前通知您。
天真地说,之所以使用这种机制,是因为在 OO 语言中,函数自然不是一等公民。如您所见,KnownNumber
和SecretNumber
仅包含生成数字的函数。一个人根本不需要这些课程。因此,在 Python 中,我们可以将它们扔掉并自行选择函数:
# OO Approach
SecretGame(SecretNumber())
SecretGame(KnownNumber())
# Functional Approach
# Dependencies
class SecretGame(object):
def __init__(self, generate):
number = generate()
print number
SecretGame(lambda: random.randint(0,10))
SecretGame(lambda: 5)
lambda 只是一个函数,它被声明为“随用随用”。 委托在 C# 中是一样的:
class Game
public Game(Func<int> generate)
Console.WriteLine(generate())
new Game(() => 5);
new Game(() => new Random().Next(0, 10));
旁注:后面的例子在 Java 7 之前是不可能的。在那里,接口是你指定这种行为的唯一方法。但是,Java 8 引入了 lambda 表达式,因此 C# 示例可以很容易地转换为 Java(Func<int>
变为 java.util.function.IntSupplier
和 =>
变为 ->
)。
【讨论】:
【参考方案2】:接口是开发中更重载和混乱的术语之一。
其实是抽象和封装的概念。对于给定的“盒子”,它声明该盒子的“输入”和“输出”。在软件的世界中,这通常意味着可以在盒子上调用的操作(连同参数),在某些情况下还意味着这些操作的返回类型。
它没有定义这些操作的语义是什么,尽管在声明附近记录它们(例如,通过 cmets)或选择好的命名约定是司空见惯的(也是非常好的做法)。然而,不能保证会遵循这些意图。
这是一个类比:看看你的电视,当它关闭时。它的界面是它的按钮、各种插头和屏幕。它的语义和行为是它接受输入(例如,有线编程)并具有输出(在屏幕上显示、声音等)。但是,当您查看未插入的电视时,您正在将预期的语义投射到界面中。就您所知,当您插入电视时,它可能会爆炸。但是,根据它的“界面”,您可以假设它不会煮任何咖啡,因为它没有进水口。
在面向对象编程中,接口通常定义了一组方法(或消息),具有该接口的类的实例可以响应这些方法(或消息)。
更令人困惑的是,在某些语言(如 Java)中,存在一个具有语言特定语义的实际接口。以Java为例,它是一组方法声明,没有实现,但一个接口也对应一个类型,并遵守各种类型的规则。
在其他语言中,例如 C++,您没有接口。类本身定义了方法,但您可以将类的接口视为非私有方法的声明。由于 C++ 的编译方式,您会获得头文件,您可以在其中拥有类的“接口”而无需实际实现。您还可以使用具有纯虚函数的抽象类等来模仿 Java 接口。
接口肯定不是类的蓝图。根据一个定义,蓝图是“详细的行动计划”。接口对动作没有任何承诺!混淆的根源在于,在大多数语言中,如果你有一个定义了一组方法的接口类型,实现它的类会“重复”相同的方法(但提供定义),所以接口看起来像一个骨架或一个课程大纲。
【讨论】:
我正在阅读一本关于 Objective-C 的书,在我看来,作者可以互换使用术语“协议”和“接口”。说“协议”和“接口”是同一件事是正确的还是我错过了什么? 我不会使用“协议”这个词来表示“接口”。 “协议”一词意味着有关如何执行操作的详细程度。 “接口”确实是一个很好的词,有一个纯英文定义,严格地描述了它是什么。 在 Windows 编程中,接口的使用相当广泛,因此即使在 C++ 中,您也可以通过与实现分离的对象的方式遇到 "interfaces"。【参考方案3】:简而言之,接口试图解决的基本问题是将我们如何使用某事物与如何实现它分开。但是你应该考虑接口is not a contract。阅读更多here。
【讨论】:
【参考方案4】:约定俗成的定义 - 接口是一种约定,它指定需要由实现它的类实现的方法。
接口的定义随着时间而改变。你认为接口只有方法声明吗? Java 5 之后的静态最终变量和默认定义呢?
接口被引入 Java 是因为具有多重继承的 Diamond 问题,而这正是他们真正打算做的事情。
接口是为解决多重继承问题而创建的结构,可以有抽象方法、默认定义和静态最终变量。
http://www.quora.com/Why-does-Java-allow-static-final-variables-in-interfaces-when-they-are-only-intended-to-be-contracts
【讨论】:
【参考方案5】:A boundary across which two systems communicate.
接口是一些面向对象语言实现ad hoc polymorphism 的方式。 Ad hoc 多态性就是在不同类型上运行的具有相同名称的函数。
【讨论】:
【参考方案6】:让我们考虑一个人(用户或对象)想要完成一些工作。他将联系一个中间人(接口),该中间人将与公司签订合同(使用实现的类创建的现实世界对象)。他将定义很少类型的工作,哪些公司将实施并给他结果。 每个公司都会以自己的方式实施工作,但结果是一样的。像这个用户将使用单个界面完成其工作。 我认为接口将充当系统的可见部分,几乎没有命令,这些命令将由实现的内部子系统在内部定义。
【讨论】:
【参考方案7】:考虑以下情况:
当一个僵尸突然袭击你时,你正在一个空荡荡的大房间中间。
你没有武器。
幸运的是,房间门口站着一个活人。
“快!”你对他大喊大叫。 “给我一些我可以打僵尸的东西!”
现在考虑: 您没有具体说明(也不在乎)什么您的朋友会选择折腾; ...不过没关系,只要:
这是可以扔的东西(他不能把沙发扔给你)
这是你可以抓住的东西(希望他没有扔手里剑)
你可以用它来敲打僵尸的大脑(不包括枕头之类的东西)
无论你得到的是棒球棒还是锤子 - 只要它实现了你的三个条件,你就很好。
总结一下:
当你编写一个界面时,你基本上是在说:“我需要一些……”
【讨论】:
其实枕头还是可以的。你可以用它打僵尸。把僵尸的大脑打爆……嗯,这是一个性能问题,从来都不是界面的一部分。【参考方案8】:如上所述,“合同”和“协议”的同义词是合适的。
接口包含您可以期望由类公开的方法和属性。
因此,如果一个类Cheetos Bag
实现了Chip Bag
接口,您应该期望Cheetos Bag
的行为与任何其他Chip Bag
完全相同。 (即暴露.attemptToOpenWithoutSpillingEverywhere()
方法等)
【讨论】:
【参考方案9】:在我看来,接口的含义比 Java 中通常与之相关的含义更广泛。我将“接口”定义为一组具有一些通用功能的可用操作,允许控制/监视模块。
在这个定义中,我试图同时涵盖程序接口和人机接口(例如,GUI)。
正如其他人已经说过的那样,就输入和输出而言,接口背后总是有一些契约。该接口不承诺任何关于“如何”操作的内容;在给定当前状态、所选操作及其参数的情况下,它只保证结果的某些属性。
【讨论】:
【参考方案10】:就我个人而言,我看到了一个类似于模板的界面。如果一个接口包含方法 foo() 和 bar() 的定义,那么你知道每个使用这个接口的类都有方法 foo() 和 bar()。
【讨论】:
【参考方案11】:接口定义了从它继承的类必须实现的内容。这样,多个类可以从一个接口继承,并且由于这种继承性,您可以
确保接口的所有成员都在派生类中实现(即使它只是为了抛出异常) 从调用者那里抽象出类本身(将类的实例转换为接口,并与它进行交互,而无需知道实际派生类是什么)有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/ms173156.aspx
【讨论】:
【参考方案12】:从技术上讲,我将接口描述为与对象交互的一组方式(方法、属性、访问器...词汇取决于您使用的语言)。如果一个对象支持/实现一个接口,那么您可以使用接口中指定的所有方式与该对象进行交互。
从语义上讲,接口还可以包含关于您可以做什么或不可以做什么的约定(例如,您可以调用方法的顺序)以及关于什么,作为回报,您可以假设对象的状态到目前为止,您进行了互动。
【讨论】:
【参考方案13】:接口将类上的操作与类内的实现分开。因此,一些实现可能会提供许多接口。
人们通常会将其描述为类方法中必须提供的内容的“合同”。
这绝对不是蓝图,因为这也将决定实施。一个完整的类定义可以说是一个蓝图。
【讨论】:
【参考方案14】:对我来说,接口是类的蓝图,这是最好的定义吗?
没有。蓝图通常包括内部结构。但接口纯粹是关于在类的外部可见的内容......或者更准确地说,是实现该接口的一系列类。
接口包含方法的签名和常量的值,以及实现接口的类和使用它的其他类之间的(通常是非正式的)“行为契约”。
【讨论】:
【参考方案15】:我不认为“蓝图”是一个好词。蓝图告诉你如何建造一些东西。一个界面专门避免告诉你如何构建一些东西。
接口定义了如何与类交互,即它支持哪些方法。
【讨论】:
我相信请求者问的是什么是定义而不是什么不是。 :)【参考方案16】:接口是您应该遵守或给予的合同,具体取决于您是实施者还是用户。
【讨论】:
我其实不喜欢这里的不合格条款合同,因为合同通常意味着语义或行为(如按合同设计)。并非所有接口都暗示任何语义或行为。例如,“墙上的洞”是真实世界的界面。无论您将其视为窗口还是垃圾处理或任何东西都是您的解释。 是的。接口是“方法签名契约”,意味着它保证实现给定的方法。它不保证它是否以任何给定的方式这样做。 没错,你应该对这个定义做更多的解释。但是接口是两个部分之间的契约。合同代码.... +1以上是关于面向对象编程中“接口”的定义是啥的主要内容,如果未能解决你的问题,请参考以下文章