23

我同意,针对接口进行编程是一种很好的做法。在大多数情况下,Java 中的“接口”在这个意义上是指语言构造接口,因此您编写一个接口和一个实现类,并且大多数时候您使用接口而不是实现类。

我想知道这是否也是编写域模型的好习惯。因此,例如,如果您有一个域类 Customer,并且每个客户可能有一个 Orders 列表,那么您通常还会编写接口 ICustomer 和 IOrder。并且客户也会有一个 IOrders 列表而不是 Orders 吗?或者你会在域模型中使用接口,只有当它真的由域驱动时,例如你有至少两种不同类型的订单?换句话说,您会因为领域模型中的技术需求而使用接口,还是仅在它真正适合实际领域时才使用接口?

4

15 回答 15

27

“仅仅因为”编写界面让我觉得浪费时间和精力,更不用说违反了 KISS 原则。

当它们实际上用于表示相关类的常见行为时,我会编写它们,而不仅仅是作为一个花哨的头文件。

于 2008-09-30T07:35:25.517 回答
12

不要过度设计你的系统。如果您发现您有几种类型的 Orders 并认为为 Orders 声明一个接口而不是在需要时重构它是合适的。对于领域模型,特定接口在开发生命周期中发生很大变化的可能性很高,因此尽早编写接口几乎没有用处。

于 2008-09-30T07:36:15.933 回答
8

接口是隔离组件以进行单元测试和一般依赖管理的绝佳方式。话虽如此,我经常更喜欢抽象类,因此至少有一些常见的行为在那里被卸载,而不是强制接口带来的一些重复。现代 IDE 可以快速轻松地生成接口,因此它们的工作量并不:-)

于 2008-09-30T07:45:11.687 回答
5

不,我只在域对象上使用接口来保持它们松散耦合。对我来说,使用接口开发自己的代码的主要钩子是我可以在进行单元测试时轻松创建模拟。我没有看到模拟域对象的意义,因为它们没有服务层或 DAO 层类所具有的相同依赖项。

这当然并不意味着偏离在域对象中使用接口。在适当的地方使用。例如,最近我一直在开发一个 web 应用程序,其中不同类型的域对象对应于用户可以在其中发表评论的永久链接页面。因此,这些域对象中的每一个现在都实现了“Commentable”接口。然后,所有基于注释的代码都被编程到 Commentable 接口而不是域对象。

于 2008-09-30T14:01:27.193 回答
4

我建议保持精益和敏捷——在你需要做之前不要做任何事情,然后让你的 IDE 在你需要的时候为你做重构。

当您决定需要一个具体类时,它在 IDEA/eclipse 中非常简单。

如果您有许多接口实现注入到您正在使用“新”的代码中的位置,则使用SpringGuice的依赖注入

于 2008-09-30T07:45:40.467 回答
4

实际上,这个问题是关于“针对接口编程”的常见误解的一个例子。

你看,这一个很好的原则,但并不很多人认为的那样!

“编程到接口,而不是实现”(来自 GoF 书中)的意思就是,您不应该竭尽全力为所有内容创建单独的接口。如果您有一个ArrayList对象,则将变量/字段/参数/返回类型声明为 type List。客户端代码将只处理接口类型。

在 Joshua Bloch 的“Effective Java”一书中,在“第 52 条:通过接口引用对象”中更清楚地表达了该原理。它甚至用粗体字说:

如果不存在适当的接口,则通过类而不是接口来引用对象是完全合适的。

对于单元测试,情况完全取决于所使用的模拟工具的功能。使用我自己的工具JMockit,我可以为使用接口和依赖注入的代码编写单元测试,就像为使用从被测代码内部实例化的最终类的代码编写单元测试一样容易。

所以,对我来说,答案是:始终使用已经存在的接口,但如果没有充分的理由,请避免创建新的接口(并且testability本身不应该是一个)。

于 2009-06-29T00:40:19.240 回答
2

在需要之前编写接口(用于测试或架构)是一种矫枉过正的做法。

此外,手动编写界面是浪费时间。您可以使用 Resharper 的重构“拉成员”让它在几秒钟内从特定类中创建新接口。与 IDE 集成的其他重构工具也应该具有类似的功能。

于 2008-09-30T11:37:11.550 回答
1

我通常只使用对较小项目有意义的接口。但是,我最近的工作有一个大型项目,其中几乎每个域对象都有一个接口。这可能有点矫枉过正,而且确实很烦人,但是我们测试和使用 Spring 进行依赖注入的方式需要它。

于 2008-09-30T07:37:30.657 回答
1

我们主要使用 Wicket、Spring 和 Hibernate 编写 Web 应用程序,并且我们使用 Spring Bean 的接口,例如服务和 DAO。对于这些类,接口是完全有意义的。但是我们也为每个域类使用接口,我认为这只是矫枉过正。

于 2008-09-30T07:40:38.560 回答
1

即使您很确定模型对象只会有一种具体类型,使用接口也可以使模拟和测试更加容易(但是现在有框架可以帮助您自动生成模拟类,即使对于具体的 Java 类也是如此 - Mockito、JTestR、Spring、Groovy...)

但我更经常将接口用于服务,因为在测试期间模拟它们更为重要,而针对接口进行编程可以帮助您考虑诸如封装之类的事情。

于 2008-09-30T07:42:25.903 回答
1

如果您将域类用于单元测试,则为域类编写接口是有意义的。我们在单元测试中使用 Mock 对象。所以,如果你有一个域对象的接口并且你的域对象本身还没有准备好,但是你的客户端可以通过模拟对象的帮助来测试它对接口的使用。

接口还为你的域模型测试你的接口的多个实现。所以,我不认为它总是矫枉过正。

于 2008-09-30T08:07:11.990 回答
1

我认为针对接口进行编程的主要原因是可测试性。因此,对于域对象 - 只需坚持 POJO 或 POC#Os :) 等,即,只需让您的类不添加任何特定框架,以防止它们具有不同的构建和运行时依赖关系,仅此而已。不过,为 DAO 创建接口是个好主意。

于 2008-09-30T08:17:29.360 回答
1

我们从所有东西中提取接口只是因为它有助于测试(模拟)和 AOP 之类的东西。Eclipse 可以自动执行此操作:Refactor->Extract Interface。

如果以后需要修改类,可以使用 Refactor->Pull Up... 将需要的方法拉到接口上。

于 2008-09-30T15:54:09.233 回答
1

*我这样做是因为我需要它来创建我的域对象的代理。

于 2008-12-18T16:47:21.370 回答
0

这是我遇到的另一件事要记住,尤其是生成的域和 DAO 对象。很多接口都太具体了。说很多领域对象都有一个ID和一个状态字段,为什么他们不共享一个通用的接口呢?这让我感到沮丧,这是一个不必要的扁平化(继承方面)域模型。

于 2008-09-30T14:45:13.907 回答