4

您何时鼓励针对接口而不是直接针对具体类进行编程?

我遵循的指导方针是在代码需要跨越逻辑/物理边界时创建抽象,尤其是在涉及与基础设施相关的问题时。

另一个检查点是,由于可能存在额外的关注代码(例如缓存、事务感知、调用 Web 服务而不是进程内执行),或者此类依赖项是否直接引用了基础设施集成点,将来依赖项是否可能会发生变化。

如果代码依赖于不需要控制来跨越逻辑/物理边界的东西,我或多或少不会创建抽象来与它们交互。

我错过了什么吗?

4

6 回答 6

6

此外,使用接口时

  • 需要以特定方式对多个对象进行操作,但本质上并不相关。也许您的许多业务对象都访问特定的实用程序对象,当他们这样做时,他们需要为自己提供对该实用程序对象的引用,以便实用程序对象可以调用特定的方法。在接口中拥有该方法并将该接口传递给该实用程序对象。

  • 将接口作为参数传递在单元测试中非常有帮助。即使您只有一种具有特定接口的对象,因此实际上并不需要定义的接口,您也可以定义/实现一个接口,只是为了在单元测试中“伪造”该对象。

  • 与前 2 个项目符号相关,请查看观察者模式依赖注入。我并不是说要实现这些模式,但它们说明了接口真正有用的地方的类型。

  • 另一个转折是实现几个 SOLID Principals、Open Closed principalsInterface Segregation principle。就像前面的子弹一样,不要因为在任何地方(至少立即)严格实施这些原则而感到压力,而是使用这些概念来帮助您将思维从仅仅考虑对象的位置转移到更多地考虑合同依赖关系

  • 最后,我们不要把它弄得太复杂:我们处于 .NET 的强类型世界中。如果您需要调用方法或设置属性,但您传递/使用的对象可能根本不同,请使用接口。

我要补充一点,如果您的代码不会被另一个库引用(至少有一段时间),那么在特定情况下是否使用接口的决定是您可以负责任地推迟的决定。如今,“提取接口”重构很容易做到。在我当前的项目中,我有一个正在传递的对象,我在想也许我应该切换到一个界面;我不是在强调它。

于 2010-02-23T16:08:48.663 回答
1

进行单元测试时,接口抽象很方便。它有助于模拟测试对象。它在 TDD 中非常有用,用于在不实际使用数据库数据的情况下进行开发。

于 2010-02-23T16:05:48.277 回答
1

如果您不需要接口中没有的类的任何特性......那么为什么不总是更喜欢接口实现呢?

它将使您的代码在将来更容易修改并且更容易测试(模拟)。

于 2010-02-23T16:07:11.190 回答
1

你有正确的想法,已经。我只会为此添加一些注释...

首先,抽象并不意味着“接口”。例如,“连接字符串”是一种抽象,即使它只是一个字符串……这与所讨论事物的“类型”无关,而是与该事物的使用意图有关。

其次,如果您正在执行任何类型的测试自动化,请寻找编写测试所暴露的痛苦和摩擦。如果您发现自己不得不为测试设置太多外部条件,这表明您需要在测试的事物和与之交互的事物之间进行更好的抽象。

于 2010-02-23T16:10:39.970 回答
1

我觉得你说得很好。其中大部分将是风格上的事情。我看过一些开源项目,其中所有东西都有接口和实现,这有点令人沮丧,但它可能会使迭代开发更容易一些,因为任何对象实现都可能中断,但假人仍然可以工作。但老实说,我可以模拟任何不会final通过继承过度使用关键字的类。

我想在你的列表中添加:任何可以被认为是黑盒子的东西都应该被抽象出来。这包括你提到的一些东西,但它也包括毛茸茸的算法,它们可能有多种有用的实现,在不同的情况下具有不同的优势。

此外,接口经常与复合对象一起派上用场。这是像 java 的 swing 库这样的东西完成任何事情的唯一方法,但它对于更普通的对象也很有用。(我个人喜欢有一个界面,比如ValidityChecker和组合或组合从属ValidityCheckers 的方式。)

于 2010-02-23T16:14:40.507 回答
0

接口传递带来的大部分有用的东西已经说过了。不过我要补充:

  • 实现一个对象或多个对象的接口,迫使所有实现者遵循相同的模式来实现与对象的契约。如果您没有如此具有 OOP 经验的程序员实际编写实现代码,这可能很有用。
  • in some languages you can add attributes on the interface itself, which can be different from the actual object implementation attribute as sense and intent
于 2010-02-23T18:37:57.813 回答