繁体   English   中英

针对接口编程:您是否为所有域类编写接口?

[英]Programming against interfaces: Do you write interfaces for all your domain classes?

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

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

编写接口“只是因为”让我感到浪费时间和精力,更不用说违反了KISS原则。

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

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

接口是隔离组件的绝佳方式,用于单元测试和一般依赖关系管理。 说,我经常更喜欢抽象类,所以至少有一些常见的行为被卸载,而不是强迫接口带来的一些重复。 现代IDE可以快速轻松地生成界面,因此它们没有那么多工作:-)

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

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

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

你看,这一个很好的原则,但并不意味着许多人认为这意味着!

“编程到一个接口,而不是一个实现”(来自GoF书)意味着,而不是你应该尽力为所有东西创建单独的接口。 如果您有一个ArrayList对象,则将变量/ field / parameter / return类型声明为List类型。 然后客户端代码只处理接口类型。

在Joshua Bloch的“Effective Java”一书中,原则在“项目52:通过接口引用对象”中更清楚地表达出来。 它甚至用粗体字母说:

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

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

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

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

它在IDEA / eclipse中非常微不足道,当你决定需要一个时,将一个具体的类变成一个接口。

然后使用依赖注入SpringGuice,如果你有很多接口实现注入代码中你正在使用'new'的地方

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

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

我通常只使用对较小项目有意义的接口。 但是,我的最新工作有一个大型项目,几乎每个域对象都有一个接口。 它可能有点过头了,这肯定很烦人,但我们测试和使用Spring进行依赖注入排序的方式需要它。

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

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

但我更经常使用接口来提供服务,因为在测试过程中模拟掉它们更为重要,而对接口进行编程可以帮助你思考像封装这样的东西。

如果您将域类用于单元测试,那么编写域类接口就有意义了。 我们在单元测试中使用Mock对象。 因此,如果您有域对象的接口,并且您的域对象本身尚未就绪,但您的客户端可以借助模拟对象测试其对接口的使用。

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

我认为针对接口编程的主要原因是可测试性。 因此,对于域对象 - 只需坚持使用POJO或POC#Os :)等,即只是让您的类不添加任何特定的框架,以防止它们产生不同的构建和运行时依赖性,这就是全部。 但是,为DAO创建接口是一个好主意。

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

如果您以后需要修改该类,可以使用Refactor-> Pull Up ...将您需要的方法提取到界面上。

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

这是另一件要记住的事情,我已经参与其中,特别是对于生成的域和DAO对象。 很多接口都太具体了。 说很多域对象都有ID和状态字段,为什么它们不共享一个公共接口? 这让我感到沮丧,这是一种不必要的扁平(继承智能)领域模型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM