为什么在服务和dao层中总是有单个实现接口?

时间:2012-01-19 06:53:32

标签: java spring design-patterns mocking domain-driven-design

我已经/看过一些spring-hibernate Web应用程序项目,它们具有与实际服务和dao类一样多的接口。

我一直认为这两个是拥有这些单一实现接口的主要原因:

  1. Spring可以将实际实现作为给定类中的依赖关系(松散耦合)

    public class Person { 
        @Autowired 
        private Address address;
    
        @Autowired 
        private AccountDetail accountDetail;
    
        public Person(Address address, AccountDetail accountDetail) 
        { // constructor
    
  2. 在单元测试中,我可以创建模拟类并单独测试类。

    Address mockedAddress = mock(Address);
    AccountDetail mockedAccountDetail = mock(AccountDetail);
    Person underTestPerson = new Person(mockedAddress, mockedAccountDetail); 
    // unit test follows
    
  3. 但是,最近,我意识到:

    Spring可以将具体实现类连接为依赖项:

    public class Person { 
    
    @Autowired 
    private AddressImpl address;
    
    @Autowired 
    private AccountDetailImpl accountDetail;
    
    public Person(AddressImpl address, AccountDetailImpl accountDetail) { 
    // constructor
    

    像EasyMock这样的模拟框架也可以模拟具体类

    AddressImpl mockedAddress = mock(AddressImpl);
    AccountDetailImpl mockedAccountDetail = mock(AccountDetailImpl);
    Person underTestPerson = new Person(mockedAddress, mockedAccountDetail); 
    // unit test follows
    

    另外,根据this讨论,我认为摘要是在单个应用程序中,界面大多过度使用可能超出惯例或习惯。在我们与另一个应用程序接口的情况下,它们通常是最有意义的,例如世界上许多应用程序使用的slf4j。在一个应用程序中,一个类几乎就像接口一样抽象。

    所以,我的问题是为什么我们仍然需要接口,然后有单个实现,如* ServiceImpl和* DaoImpl类,并不必要地增加我们的代码基本大小。在嘲笑我不知道的具体课程时是否存在一些问题。

    每当我和我的队友讨论这个问题时,我得到的答案就是实现基于接口的服务和dao类是每个人都遵循的设计 - 他们提到了春季最佳实践,OOP,DDD等。但我仍然在隔离的应用程序中拥有如此多的接口背后,没有一个实用的理由。

2 个答案:

答案 0 :(得分:16)

接口有更多优点 - 就像在代理中一样。如果您的类实现了接口,则默认情况下将为AOP使用JDK动态代理。如果直接使用实现,则会通过使proxy-target-class = true强制使用CGLIB代理。与JDK代理不同,它们需要字节代码操作。

请阅读here了解更多信息。

请阅读what reasons are there to use interfaces (Java EE or Spring and JPA)处的其他讨论以获取更多信息。

答案 1 :(得分:16)

这是一个非常有争议的话题。简而言之,没有 - 至少对你而言,开发者。

在EJB2世界中,Home和Remote接口是必须的,而且正是出于某种原因@AravindA提到:代理。安全性,远程处理,池化等都可以包含在代理中,并严格在标准库中提供所请求的服务(如DynamicProxy)。

现在我们有javaassistcglib,Spring(Hibernate,EJB3,如果你愿意的话)完全能够像框架开发人员喜欢的那样检测你的类。问题是,他们做的是一件非常讨厌的事情:他们通常会要求你添加一个无参数的构造函数.-等等,我在这里有参数?-Nevermind,只需添加构造函数。

所以接口就是为了保持你的理智。但是,奇怪的是,具有适当构造函数的类的无参数构造函数对我来说并不合适,对吧?事实证明(我应该阅读规范,我知道)Spring创建了类的接口的功能等价物:没有(或忽略)状态的实例和所有覆盖的方法。所以你有一个“真正的”实例和一个“假接口”实例,假接口的作用是什么,它为你提供所有的安全/事务/远程魔术。很好,但很难理解,如果你没有将它拆开,看起来像一个bug。

此外,如果您碰巧在您的类中实现了一个接口,(至少某些版本)Spring突然决定您只代理此接口,并且该应用程序无法正常工作。

因此,到目前为止,原因是安全和理智。有理由说这是一个很好的做法 - 但是从你的帖子中,我看到你已经阅读了所有这些。我今天能看到的最重要的原因是WTH /分钟指标,特别是如果我们谈论你的项目的新人。

相关问题