基本介绍
依赖倒转原则(Dependence Inversion Principle)是指:
- 细节应该依赖抽象
- 依赖倒转(倒置)的本质是面向接口编程
- 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。在Java中,抽象指的是接口或抽象类,细节就是具体的实现类
- 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
反例:
public class Sms {
public String getMsg(){
return "hello world";
}
}
public class Mobile {
public void receiveMsg(Sms sms){
System.out.println(sms.getMsg());
}
}
public class Main {
public static void main(String[] args) {
Mobile mobile = new Mobile();
Sms sms = new Sms();
mobile.receiveMsg(sms);
}
}
如上Mobile类的receiveMsg方法参数是具体的对象Sms,如果以后还需要接收其他类型的数据,比如微信等,需要重新写方法,非常不利于扩展,改动大。
正例:
改成面向接口对象即可。
public interface IMsg {
String getMsg();
}
public class Sms implements IMsg{
public String getMsg(){
return "hello world";
}
}
public class WeChatMsg implements IMsg{
@Override
public String getMsg() {
return "WeChat is ok";
}
}
public class Mobile {
public void receiveMsg(IMsg sms){
System.out.println(sms.getMsg());
}
}
public class Main {
public static void main(String[] args) {
Mobile mobile = new Mobile();
IMsg sms = new Sms();
mobile.receiveMsg(sms);
IMsg weChatMsg = new WeChatMsg();
mobile.receiveMsg(weChatMsg);
}
}
依赖关系传递的三种方式和应用案例
- 接口传递
public interface Run {
void run();
}
public interface Fly {
void flyHigh(Run run);
}
public class QuickRun implements Run{
@Override
public void run() {
System.out.println("飞奔。。。");
}
}
public class DuckFly implements Fly{
@Override
public void flyHigh(Run run) {
run.run();
System.out.println("飞不高");
}
}
public class Main {
public static void main(String[] args) {
Run quickRun = new QuickRun();
Fly duckFly = new DuckFly();
duckFly.flyHigh(quickRun);
}
}
- 构造方法传递
public interface Run {
void run();
}
public interface Fly {
void flyHigh();
}
public class QuickRun implements Run {
@Override
public void run() {
System.out.println("飞奔。。。");
}
}
public class DuckFly implements Fly {
Run run;
public DuckFly(Run run) {
this.run = run;
}
@Override
public void flyHigh() {
run.run();
System.out.println("飞不高");
}
}
public class Main {
public static void main(String[] args) {
Run quickRun = new QuickRun();
Fly duckFly = new DuckFly(quickRun);
duckFly.flyHigh();
}
}
- setter 方法传递(较少使用)
public interface Run {
void run();
}
public interface Fly {
void flyHigh();
}
public class QuickRun implements Run {
@Override
public void run() {
System.out.println("飞奔。。。");
}
}
public class DuckFly implements Fly {
Run run;
@Override
public void flyHigh() {
run.run();
System.out.println("飞不高");
}
public Run getRun() {
return run;
}
public void setRun(Run run) {
this.run = run;
}
}
public class Main {
public static void main(String[] args) {
Run quickRun = new QuickRun();
DuckFly duckFly = new DuckFly();
duckFly.setRun(quickRun);
duckFly.flyHigh();
}
}
依赖倒转原则的注意事项和细节
-
低层模块最好有接口或者实现类,这样程序稳定性好
-
变量的声明尽量是抽象类或者方法,这样变量引用和实际对象间有了一个缓冲,利于程序的扩展和优化
比如我们方法参数常用List 而不是ArrayList,这样当我们需要LinkedList的时候,方法不需要改变什么就可以直接使用了。
-
继承时要遵循里氏替换原则(下节内容)
解释:每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块,原子逻辑的再组装就是高层模块