依赖倒置原则

用户头像
Jeff先生
关注
发布于: 2020 年 06 月 17 日
依赖倒置原则



一、聊聊依赖倒置

几年前的一天,有人要和我讨论依赖倒置,我当时就觉得这个东西是个java程序员肯定耳朵都听出茧了,不就是A->B变成B->A么,有啥好讨论的!知道之后学习DDD再接触依赖倒置的时候我才突然惊醒,事实上我从来没真正的懂过和用过。

我们用springmvc来举例,有一个典型的项目结构示例:

这个结构里面services模块是负责具体的业务实现的服务,有一些编程经验的人都知道面向接口编程,所以service至少会拆分成两部分一个是接口的模块client,一个是接口的实现server。一般来说admin会依赖services这个大模块,然具体实现的时候使用的是client里面的接口:



依赖倒置的核心是依赖抽象。上面这个项目结构仍然是正向依赖,首先admin依赖了services这个大模块,这个模块里面包含了具体的实现:server,另外你肯定是先写好client里面的方法,然后admin再决定调用哪些方法来做上层业务。第二点通常会让人感到疑惑,尤其是在写业务代码而且admin和services都是一个人来实现的时候。针对第一点的解决方式咱可以说admin不依赖services整个大模块,只需要依赖下面的client模块就行,这样admin就没有依赖具体实现了,这样说没有问题,那么你可能就需要添加一个额外的模块来打包整个项目,因为实现类是一定最终需要加进来的(还有其他的实现方式)。针对第二点解决方法我可能解释的不是很好,但是我还是要努力的解释:admin依赖client里面的接口是需要完成具体的功能,如果client里面有100个接口,而admin依赖client完成的事情其实只要两件(比如注册、登陆),那么这个时候admin依赖client仍然会增加很多我不需要的东西,会被污染。另外如果我们让两个人各自来实现这个client,最后生成了clientA和clientB。admin需要有判断逻辑来切换clientA,clientB?如果你负责操刀admin,你会怎么做呢?是的,依赖倒置就行了,让admin去定义好需要的登陆和注册接口,让services去依赖admin,这样我admin不关心clientA和clientB定义的是什么接口,反而是你们都得实现我需要的接口。



上面的例子其实不是严格实例,但是确实有一定程度上的依赖倒置的意思。严格一点我们可以把client抽离到最外层把它定义成一种规范,admin依赖它,services实现它。



二、tomcat中的依赖倒置

依赖倒置在写业务代码的时候其实用的会比较少一些,因为代价比较高,更多人的思维天然的偏过程,尤其在小公司,时间紧迫,试错的需求比较多。依赖倒置在框架(web容器)中用的比较多,比如tomcat,tomcat遵循servlet规范,实现自己内部逻辑的时候就依赖规范中提供的抽象,只要我们的web程序遵循servlet规范并实现了它,tomcat就能把从用户端接受到的请求,web程序也能把响应结果返回给tomcat转到用户端。用好莱坞的说法就是:只要你开发的java程序遵循了我tomcat的规范,你不要来问我什么时候要调用你,你等着我调用你就行--好莱坞规则。



三、接口隔离

非常出名的SOLID规则包括,单一职责(S),开闭规则(O),里式替换(L),接口隔离(I),依赖倒置(D)。其中接口隔离的白话描述就是:假设我有一个接口里面有a、b、c、d四个方法,其中ab是读方法,cd是写方法,如果这个接口被用于的单一业务场景是ab->cd,把adcd都用上,那么我们就不用做什么更改。但是当业务发生改变,abc我们希望继续让用户使用,d我们不再希望对外暴露的时候怎么办呢。是的,把一个接口拆成两个接口,通过接口隔离的方式把d隐藏起来。比如下面这个例子:





暂定业务场景:供客户端使用的cache服务,rebuild用于远程控制客户端的cache更新。服务端把缓存内容推送到客户端本地,客户端调用get方法的时候获取本地缓存,服务端如果有更新的时候会调用rebuild方法更新本地缓存。那么现在问题来了,我们不应该让客户端感知到这个rebuild方法,不然它自己瞎用,本地给清空了怎么办。解决方案就是把这个Cache接口分拆,如下:



这样客户端实现CacheService就行,rebuild对客户端就不可见了。



发布于: 2020 年 06 月 17 日 阅读数: 47
用户头像

Jeff先生

关注

还未添加个人签名 2018.03.31 加入

还未添加个人简介

评论

发布
暂无评论
依赖倒置原则