为得到良好的阅读体验,请访问原文:传送门html
依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,高层模块不该该依赖低层模块,两者都应该依赖其抽象。java
抽象不该该依赖细节,细节应该依赖抽象。经过依赖倒置,能够减小类与类之间的耦合性,提升系统的稳定性,提升代码的可读性和可维护性,而且可以下降修改程序所形成的风险。git
但是依赖倒置原则是怎么作到的呢?咱们先来看一个例子:一个爱学习的「我没有三颗心脏」同窗如今正在学习「设计模式」和「Java」的课程,伪代码以下:github
public class Wmyskxz { public void studyJavaCourse() { System.out.println("「我没有三颗心脏」同窗正在学习「Java」课程"); } public void studyDesignPatternCourse() { System.out.println("「我没有三颗心脏」同窗正在学习「设计模式」课程"); } }
咱们来模拟上层调用一下:编程
public static void main(String[] args) { Wmyskxz wmyskxz = new Wmyskxz(); wmyskxz.studyJavaCourse(); wmyskxz.studyDesignPatternCourse(); }
因为「我没有三颗心脏」同窗热爱学习,随着学习兴趣的 “暴增”,可能会继续学习 AI(人工智能)的课程。这个时候,由于「业务的扩展」,要从底层实现到高层调用依次地修改代码。设计模式
咱们须要在 Wmyskxz 类中新增 studyAICourse()
方法,也须要在高层调用中增长调用,这样一来,系统发布后,实际上是很是不稳定的。显然在这个简单的例子中,咱们还能够自信地认为,咱们能 Hold 住这一次的修改带来的影响,由于都是新增的代码,咱们回归的时候也能够很好地 cover 住,但实际的状况和实际的软件环境要复杂得多。微信
最理想的状况就是,咱们已经编写好的代码能够 “万年不变”,这就意味着已经覆盖的单元测试能够不用修改,已经存在的行为能够保证保持不变,这就意味着「稳定」。任何代码上的修改带来的影响都是有未知风险的,不论看上去多么简单。架构
另一点,你有没有发现其实加上新增的 AI 课程的学习,他们三节课本质上行为都是同样的,若是咱们任由这样行为近乎同样的代码在咱们的类里面肆意扩展的话,很快咱们的类就会变得臃肿不堪,等到咱们意识到不得不重构这个类以缓解这样的状况的时候,或许成本已经变得高得可怕了。ide
《资本论》中有这样一段描述:单元测试
在商品经济的萌芽时期,出现了物物交换。假设你要买一个 iPhone,卖 iPhone 的老板让你拿一头猪跟他换,但是你并无养猪,你只会编程。因此你找到一位养猪户,说给他作一个养猪的 APP 来换他一头猪,他说换猪能够,可是得用一条金项链来换...
因此这里就出现了一连串的对象依赖,从而形成了严重的耦合灾难。解决这个问题的最好的办法就是,买卖双发都依赖于抽象——也就是货币——来进行交换,这样一来耦合度就大为下降了。
咱们如今的代码是上层直接依赖低层实现,如今咱们须要定义一个抽象的 ICourse 接口,来对这种强依赖进行解耦(就像上面《资本论》中的例子那样):
接下来咱们能够参考一下伪代码,先定一个课程的抽象 ICourse 接口:
public interface ICourse { void study(); }
而后编写分别为 JavaCourse
和 DesignPatternCourse
编写一个类:
public class JavaCourse implements ICourse { @Override public void study() { System.out.println("「我没有三颗心脏」同窗正在学习「Java」课程"); } } public class DesignPatternCourse implements ICourse { @Override public void study() { System.out.println("「我没有三颗心脏」同窗正在学习「设计模式」课程"); } }
而后把 Wmyskxz 类改形成以下的样子:
public class Wmyskxz { public void study(ICourse course) { course.study(); } }
再来是咱们的调用:
public static void main(String[] args) { Wmyskxz wmyskxz = new Wmyskxz(); wmyskxz.study(new JavaCourse()); wmyskxz.study(new DesignPatternCourse()); }
这时候咱们再来看代码,不管「我没有三颗心脏」的兴趣怎么暴涨,对于新的课程,都只须要新建一个类,经过参数传递的方式告诉它,而不须要修改底层的代码。实际上这有点像你们熟悉的依赖注入的方式了。
总之,切记:以抽象为基准比以细节为基准搭建起来的架构要稳定得多,所以在拿到需求后,要面相接口编程,先顶层设计再细节地设计代码结构。
按照惯例黏一个尾巴:
欢迎转载,转载请注明出处!
独立域名博客:wmyskxz.com
简书ID:@我没有三颗心脏
github:wmyskxz 欢迎关注公众微信号:wmyskxz 分享本身的学习 & 学习资料 & 生活 想要交流的朋友也能够加qq群:3382693 钱