“基于接口的编程”究竟是什么?

21

我经常听/读到关于基于接口的编程,但我不太清楚这到底是什么意思。基于接口的编程是一个独立的主题吗?是否有书籍介绍了相关内容?如果有,有没有人能推荐几本好书呢?

我在阅读有关良好API设计的文章时发现了基于接口编程,并希望了解更多信息。目前我还不清楚如何正确地围绕接口设计API。

非常感谢任何信息。


这是一个重复的问题。例如,请参考问题1413543(https://dev59.com/8nM_5IYBdhLWcg3wWRuV)。 - jason
你可能想看看《Head First 设计模式》这本书。虽然例子是用 Java 写的,但这是一个很好的起点。 - kragan
1
@Jason:编程到接口并不一定等于基于接口的编程。 "基于接口的编程" 不仅仅意味着使用接口,通常它更是一种架构上的决策。 - Reed Copsey
8个回答

33
基本上,它是关于以接口而非具体类(或更糟的静态方法)来表达您的依赖关系。因此,如果您的其中一个类需要执行身份验证,则应提供一个(或其他内容)。
这意味着:
  • 您可以在实现真正的依赖性之前编写代码
  • 您可以通过模拟测试(无需模拟类,这会变得丑陋)
  • 以API形式而非具体实现形式清晰地表示您所依赖的内容(即,您有更松散的耦合)

有没有一本好书能够解释这种 C# 编程的“风格”? - koumides
1
@koumides:没有特别指定,但搜索“控制反转”和“依赖注入”可以找到很多文章。 - Jon Skeet

9
《实用 API 设计》 第六章的标题是“针对接口编程,而非实现”,它解释了通过针对接口而非特定实现进行编码,可以将系统中的模块(或组件)解耦,从而提高系统质量。

OOSC2 中的 Bertrand Meyer 清楚地解释了为什么“关闭”系统并使其更加模块化会提高其质量。



4
你所说的“基于接口编程”更常被称为面向接口编程。以下是一个例子。好处在于隐藏接口的实际实现,使你的代码在未来更加灵活和易于维护。
YourInterface foo = CreateYourInterface();
foo.DoWork();
foo.DoMoreWork();

CreateYourInterface()将返回YourInterface的具体实现。这允许您通过更改一行代码来更改应用程序的功能:
YourInterface foo = CreateYourInterface();

你修改了哪一行代码?能具体说明一下吗? - DOK
我所提到的那一行是指:YourInterface foo = CreateYourInterface()。我只是在指出,如果你将一个实现了同样接口的不同对象分配给 foo,那么你会得到不同的功能,但代码保持相同。 - Taylor Leese

3
如果你在谷歌上搜索“接口”,你会找到很多关于接口有多么有用的信息。
这个概念是定义清晰的接口,各种组件/部分/类/模块将使用它们来进行通信和交互。一旦你定义了这些接口的输入/输出应该是什么,你就可以让各个团队开发任何需要满足接口要求的东西,包括输入/输出测试等等。
如果你遵循这个模式,各个团队可以开始开发他们的部分,而不必等待其他部分准备好。此外,你还可以使用单元测试(使用虚拟对象来模拟你没有开发的其他部分,并测试你的部分)。
这种方法对于任何新的编程项目来说都是相当标准的,每个人都会认为这是理所当然的。

2

我不建议在C#开发中过度使用这个。

基于接口的编程基本上是指针对接口进行编程。您开发要使用的接口和合同,接口的实际实现隐藏在这些合同后面。

在.NET之前,这是非常普遍的,因为在Windows上获得可重用组件的最佳方法是通过COM,它在任何地方都使用接口。然而,鉴于.NET能够支持单个运行时(CLR)中的多种语言,并且与本机代码相比,在版本控制方面具有更好的支持,因此在使用C#进行编程时,基于接口的编程的实用性大大降低(除非您尝试创建COM组件,在这种情况下,您仍将间接从C#类创建COM接口)。


对于那些给我负反馈的人:我并没有表示接口本身有问题——相反,我认为仅围绕接口设计整个API的“基于接口的编程”方法不一定像在COM时代那样对C#开发人员有用。 - Reed Copsey
模拟接口比具体类容易得多(特别是没有虚方法的密封类)。我仍然相信这可以澄清你真正依赖的内容... - Jon Skeet
@Jon SKeet:没错。模拟接口比密封或非虚类更容易,但抽象类同样易于模拟,并且在版本控制方面具有一些优势,如果您正在使用标记了问题的C#语言。 - Reed Copsey
如果有人能够详细解释一下他们对这个答案的不满,我会非常感激。 - Reed Copsey
好的,Reed,我没有给你投反对票。但是我不太明白支持多种语言和版本控制与讨论的相关性。虽然我理解这可能是从 COM 的好日子延续下来的一部分。 - DOK
@DOK:接口编程之所以首次被需要,很大程度上是为了支持多种语言/技术制造可重用的组件。.NET提供了许多相同的支持,因此许多在COM世界中使用IEverything和其他基于接口的编程方法的需求都由.NET框架自动处理,而无需接口。 - Reed Copsey

1

基于接口的编程可以被认为是将功能的实现和访问功能的方式解耦。

您定义一个接口
interface ICallSomeone { public bool DialNumber(string number); }

然后编写您的实现

public class callsomeone: ICallSomeone {
public bool DialNumber(string number) {
//拨打号码,返回结果 }}

您使用接口而不关心实现。如果更改实现,因为它只使用接口,所以没有任何影响。


0

从非常抽象的角度来看,基于接口的编程类似于管道工使用的组件(管接头和管道)。

只要管道和接头按照指定的接口制造(例如螺纹数量和间隔等),各种制造商就可以为潜在由其他供应商制造的管子提供接头(但遵守前述的接头/管道接口)。

因此,组件之间的互操作性更强,管道工可以选择来自各个供应商的不同产品、价格范围等,以创建功能完善的管道系统。

将管子和接头替换为软件组件,相似之处惊人地简单。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接