依赖倒置
依赖倒置是面对对象设计的标志,依赖于抽象或接口进行编程。
What
Dependence Inversion Principle (DIP) ,高层模块应该依赖于抽象,而不能直接依赖底层模块的具体实现
Why
传统的:修改功能时,必须修改底层模块原有的实现代码,甚至导致修改高层模块代码。违背了开放封闭原则。
底层模块(具体实现)--> 高层模块(调用底层模块实现用户场景功能)
依赖倒置后:只要抽象/接口不变,高层模块就不用变化。修改实现代码也可通过新增代码文件来实现,而不需要修改原有代码。
抽象/接口 --> 底层模块(实现接口的具体功能)
抽象/接口 --> 高层模块(调用接口实现用户场景功能)
How
三个模块
- IService
- ServiceImpl
- UI
调用流程
- IService-> ServiceImpl
- UI层通过注入赋值得到IService实例
- UI层功能-> IService.execute();
控制反转
new
对象地方的转移
What
Inversion of Control(IoC) :对象控制权(new对象的权利)进行转移,转移到第三方,比如交给IoC容器,它就是一个创建对象的工厂,你要什么对象,它就给你什么对象。有了IoC容器,原来的依赖关系就没了,都变成了依赖IoC容器了。
why
一般程序流程
UI层功能1-> new ServiceImpl(param1, param2, param3)
UI层功能2-> new ServiceImpl(param1, param2, param3)
UI层功能3-> new ServiceImpl(param1, param2, param3)
以上设计需要UI层里面new ServiceImpl()
,从而导致依赖了底层的具体实现,会有如下缺点:
- 依赖了底层的具体实现,违反了依赖倒置原则
- 需要多次new一个ServiceImpl对象,浪费资源
- UI层需要知道如何怎么ServiceImpl的构造参数,依赖哪些对象,从而增加代码复杂度,并产生很多重复代码
可以利用控制反转的思想解决上述缺点
how
两个实现方法:
- 依赖注入
- Service Locator
依赖注入
Dependency Injection
让IoC容器去new
ServiceImpl实例,并通过“注入”的方式赋值给UI层。实现和底层ServiceImpl的解耦
Service Locator
让UI层全部依赖ServiceLocator,由ServiceLocator提供各种ServiceImpl实例,实现和底层ServiceImpl的解耦
一般流程:
- ServiceLocator.registerService();
- ServiceLocator.getServcie();
|
疑问?
ServieImpl的new
是在ServiceLocator中呢,还是其他地方?还是都可以
依赖注入和Service Locator对比
- Service Locator允许你在一个类 中“解决”依赖问题
- DI允许你从类外“注入”依赖
- 当使用service locator时,每个类都有一个对service locator的依赖