【问题标题】:Service and DAO always implement interfacesService 和 DAO 总是实现接口
【发布时间】:2013-08-27 23:33:27
【问题描述】:

在我见过的所有 MVC 项目中,“服务”和“DAO”类总是实现自己的接口。但几乎所有时候,我都没有看到有这个界面有用的情况。

在这些情况下是否有任何理由使用接口?在“服务”和“DAO”类中不使用接口可能会导致什么后果?我无法想象任何后果。

【问题讨论】:

    标签: java spring spring-mvc


    【解决方案1】:

    Spring 是一个控制反转容器。从某种意义上说,这意味着您使用的类的实现不取决于应用程序,而是取决于其配置。如果您有一个需要 UserRepository 来存储 User 实例的类,则类似于

    class UserService {
        @Autowired
        private UserRepository userRepository;
    }
    
    interface UserRepository {
        List<User> getUsers();
        User findUserBySIN(String SIN);
        List<User> getUsersInCountry(Long couyntryId);
    }
    

    你会为它声明一个 bean

    <bean class="com.myapp.UserRepositoryHibernateImpl">
       ...
    </bean>
    

    注意这个 bean 是 UserRepositoryHibernateImpl,它将实现 UserRepository

    在世界未来的某个时刻,Hibernate 项目不再受支持,您确实需要一个仅在 Mybatis 上可用的功能,因此您需要更改实现。因为您的UserService 类使用了以接口类型声明的UserRepository,所以只有接口上可见的方法对类可见。因此更改userRepository 的实际多态类型不会影响客户端代码的其余部分。您需要更改的所有内容(不包括创建新类)是

    <bean class="com.myapp.future.UserRepositoryMyBatisImpl">
       ...
    </bean>
    

    您的应用程序仍然有效。

    【讨论】:

    • 但是如果你要从UserRepositoryHibernateImpl 切换到UserRepositoryMybatisImpl,那么无论如何你都必须写一大堆代码。所以你肯定会重建你的应用程序。为什么更改一行 Java(userRepository 的变量声明)不如更改一行 XML(bean 声明)有吸引力?这确实不是首选接口的论据。
    • UserRepositoryHibernateImplUserRepositoryMybatisImpl 都实现了一些 UserRepository 接口。所有交互都是通过该接口完成的。所以切换它背后的东西非常容易。客户不变。如果它们是通过与实现的特定交互来完成的,那么您将不得不更改与之交互的代码。使用接口,您不需要。使用 Spring,您可以在上下文中通过简单的声明来指定实现。
    • 是的,我明白这一切。我只是不相信炒作。
    • @DavidWallace 我猜你必须再体验几次。
    • 是的,我和 OP 都有。
    【解决方案2】:

    有很多支持接口的论据,请参阅 Google。

    我可以补充其他人提到的观点:

    1. 假设您将 DAO 实现从 Hibernate 更改为 iBatis。依赖于接口而不是实现将对服务层有很大帮助。
    2. 如果您使用 AOP 或使用 JDK 动态代理的代理,那么您的类必须实现接口。 CGLIB 并非如此。
    3. 在服务层中,如果您想将自己的方法发布给其他客户端进行调用,则将它们“作为合同的接口”比实现更有意义。
    4. 如果您想将 services.jar 与 daos.jar 分开,那么在您的 daos 上设置接口可以避免重新编译 services.jar,以防 daos.jar 发生变化。

    总之,有接口就好了!

    【讨论】:

      【解决方案3】:

      基于接口的实现有助于在测试套件中模拟它们。在我们的项目中,在测试服务层时,我们模拟 DAO 并提供硬编码数据,而不是真正连接到数据库。同样的论点也适用于服务层。

      【讨论】:

      • 但是有一些模拟框架可以像模拟接口一样轻松地模拟类。我不认为这是分离接口的论据。
      【解决方案4】:

      尽早使用接口使您的应用程序具备可扩展性,不使用它的后果是牺牲应用程序的可扩展性。

      【讨论】:

        【解决方案5】:

        我最近一直在问自己同样的问题,我觉得即使我知道会有一个实现类也创建一个接口是愚蠢的并且会增加臃肿(每个尝试更实用语言的 Java 程序员会知道感觉)。那是另一个编译模块,通常只是为了满足一个人内心的教条主义者。

        Spring 似乎已经演变成一个面向模块/组件的框架,程序员只创建块,框架将它们组装在一起。这就是为什么让多个 bean 匹配标准是一个问题并且使事情复杂化的原因(你最终会使用限定符,这会扼杀 DI 的目的)。程序员自然会尽量避免类型歧义,以尽量减少所需配置的数量,理想情况下使任何给定的块只适合一个“槽”。

        在我看来,DI 的最大优势不是它使更改实现变得容易(通过简单地更改配置 XML 中声明的类的类型),而是它允许更容易地分离依赖关系,从而更容易分开测试每个组件。你不需要单子接口。

        由于对类进行逆向工程以提取其接口将是一项纯粹的机械任务,因此我不会担心“如果我需要添加另一个实现怎么办?”论据。

        免责声明:中小型应用开发者的意见;我确信情况会随着大型项目而改变。

        【讨论】:

          猜你喜欢
          • 2012-09-21
          • 2012-07-04
          • 1970-01-01
          • 2011-12-28
          • 2019-12-28
          • 1970-01-01
          • 2020-06-25
          • 1970-01-01
          • 2018-11-18
          相关资源
          最近更新 更多