依赖倒置原则
1、什么是依赖倒置原则(Dependence Invarsion)
- 高层模块不应该依赖于低层模块,他们都应该依赖于抽象。
- 抽象不应该依赖于细节,细节应该依赖于抽象。
1.1、依赖倒置中设计到的名词概念
- 。
依赖:首先依赖倒置中的依赖并不是uml六种关系中的依赖。依赖倒置原则中的依赖,指的是A要做一件事必须要用到B,如果不用B那么这件事就干不了。如果对应到代码中,可以表现为uml六种关系,对应的代码。
倒置:变成与原来位置方向相反的状态。
模块:在程序设计中,指能够独立完成一定功能的程序语句的集合。
高层模块:例如在小区这个环境中,小区相对于楼小区就是高层模块。你没有小区,你就没有一栋楼,没有一栋楼,你就不可能有个单元。你没有单元,你就没有厨房,没有厨房,你就没有锅碗瓢勺和炉灶,没有罐,苗条和炉灶。
例如:在父子关系中,爸爸相对于儿子来说爸爸就是高层模块。
抽象:从多个事物中,抽取出共同,本质性的特征。在java中抽象可以是抽象类和接口。
细节:起到关键作用的小事,在java中细节可以是具体的实现类
依赖倒置的应用场景
- 例如在程序设计中,高层模块类A直接依赖于类B,现在假设将类A改为依赖于类C,这个时候我们就需要修改类A中的代码。推而广之我要是将类A改为依赖于DEF等等类,那么类A的改动就更大了。
这个时候的解决方案:可以将类A依赖于接口I,让类B 和类C去实现接口I,这个时候如果有其他的需求,比如增加类EDF,那么可以直接去实现接口I。就避免修改类A,类A通过接口I间接与类B或者类C发生联系。就会很大程度上降低修改类A的几率。
依赖倒置解决了什么样的问题
- 细节往往是多变的,抽象的东西要稳定很多,就好比以抽象为基础搭建起来的架构比以细节为基础搭建起来的架构要稳定的多。这一点就和面向对象的基本的特点就十分吻合,易扩展,易维护、易复用。关注谁来干事,由多少人来干,而不是怎么干。
示例
业务场景某程序连接的是SQLServer数据库来管理在使用程序产生的数据。
未使用依赖倒置原则
public class Application { public void connect(SQLServer sqlServer){ System.out.println("开始进行连接数据库"); System.out.println(sqlServer.getContent()); } }
public class SQLServer { public String getContent(){ return "成功连接到SQLServer数据库"; } }
public class Client { public static void main(String[] args) { Application application=new Application(); application.connect(new SQLServer()); } }
假如有一天,这个应用由于需要更换为Mysql的数据库,需要让这个应用连接mysql的数据库。mysql的代码如下:
public class Mysql { public String getContent(){ return "成功连接到Mysql数据库"; } }
这个时候我们就需要修改Application这个类,严重点相当于我要停掉我们的程序一段时间仅仅去修改一个连接数据库的代码,对公司造成的损失太大对公司开发的这个程序造成的影响太大了。
原因就是Application类与SQLServer之间的耦合度太高了,必须要降低他们之间的耦合度。
使用依赖倒置原则
我们引入一个抽象的IDataBaser。数据库管理者,,用于管理所有数据库。
public interface IDataBase { public String getContent(); }
Application类与接口IDataBase发生依赖关系,而Mysql和SQLserver都属于数据库的范畴,他们各自去实现IDataBase接口。
代码修改为
public class Application { public void connect(IDataBase iDataBase){ System.out.println("开始进行连接数据库"); System.out.println(iDataBase.getContent()); } } public interface IDataBase { public String getContent(); } public class SQLServer implements IDataBase { public String getContent(){ return "成功连接到SQLServer数据库"; } } public class Mysql implements IDataBase { public String getContent(){ return "成功连接到Mysql数据库"; } } public class Client { public static void main(String[] args) { Application application=new Application(); application.connect(new SQLServer()); application.connect(new Mysql()); } }
这样修改之后,无论之后怎么扩展Client无论添加什么样的数据库如Oracle,MongoDB,MariaDB,Dynamo等都不需要修改Application类。在实际情况中,代表高层模块的Application类将负责完成功能主要的业务逻辑,一旦对他进行修改,引入错误的风险很大,所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。