首先,什么是依赖反转,为什么叫反转?

高层不应该依赖细节,细节应该依赖高层。


什么是高层?什么是细节?对一个系统来说,业务逻辑是高层,其他是细节。业务逻辑是仅仅包括用例、业务实体部分,不包括任何框架、存储(数据库)、其他系统等部分,是纯粹的。其他细节,包括框架、数据库、消息队列,都是细节。业务逻辑应该不依赖任何细节。细节的实现可以任意替换而不影响业务逻辑。这样的业务逻辑,可以测试、容易测试。

拿通常的Java Web应用来说,一般我们使用的包括:Controller->Service->DAO->数据库。 其中,Service是高层,包含业务逻辑,其他都是细节。

为什么叫“反转”,从调用顺序来讲,Service是依赖DAO来实现业务数据的存取的,那么这时候高层就依赖了细节。但如果我们在Service层抽象一个DAO接口,让实际的DAO从这个接口派生一个类出来。那么Service这个模块就不依赖于DAO的实现,而是依赖了一个内部的接口。这样调用的方向和依赖的方向就相反了,称之为“反转”。例子:【Service->IDAO】<-DAOImpl->数据库。

依赖注入和依赖反转的关系

依靠框架的依赖注入功能,我们很容易实现依赖反转的时候实现实例的注入。

业务对象:

public class QuizServiceImpl implements QuizService {
    private BankDAO bankDAO;
    private QuizDAO quizDAO;

 在业务对象里面,我们定义了两个DAO,都是接口。

在外部实现的时候,我们首先派生两个对象,实现这两个DAO接口。然后用Spring的Configuration功能,将这些接口的实现注入到Service中。Service完全不知道Spring框架、数据库的存在,他只关注自己的业务逻辑,以及自己声明的两个DAO接口。

@Configuration
public class ServiceConfig {
    @Bean
    BankDAO bankDAO(){
        return new MemoryBankDAOImpl();
    }
    @Bean
    QuizDAO quizDAO(){
        return new MemoryQuizDAOImpl();
    }
    @Bean
    QuizService quizService(BankDAO bankDAO,QuizDAO quizDAO){
        QuizServiceImpl quizService=new QuizServiceImpl();
        quizService.setBankDAO(bankDAO);
        quizService.setQuizDAO(quizDAO);
        return quizService;
    }
    @Bean
    QuestionAdminService questionAdminService(BankDAO bankDAO){
        QuestionAdminServiceImpl questionAdminService=new QuestionAdminServiceImpl();
        questionAdminService.setBankDAO(bankDAO);
        return questionAdminService;
    }
}

  这样我们就可以在Controller等地方,使用@Autowired对QuiService进行自动注入。而Service完全不知道这些细节的存在!当然也就不存在依赖。

通过依赖反转,高层的业务逻辑和各种细节完全解耦。你甚至可以这么做:一个工程写业务逻辑,然后打包成一个jar,另外一个实现的工程引用这个jar,把数据库、Controller等实现了,完成完整功能。

posted on 2018-02-27 09:21  邓志国  阅读(2149)  评论(0编辑  收藏  举报