0%

依赖倒置

依赖倒置

依赖倒置是面对对象设计的标志,依赖于抽象或接口进行编程。

What

Dependence Inversion Principle (DIP) ,高层模块应该依赖于抽象,而不能直接依赖底层模块的具体实现

Why

传统的:修改功能时,必须修改底层模块原有的实现代码,甚至导致修改高层模块代码。违背了开放封闭原则。

底层模块(具体实现)--> 高层模块(调用底层模块实现用户场景功能)

依赖倒置后:只要抽象/接口不变,高层模块就不用变化。修改实现代码也可通过新增代码文件来实现,而不需要修改原有代码。

抽象/接口 --> 底层模块(实现接口的具体功能)
抽象/接口 --> 高层模块(调用接口实现用户场景功能)

How

三个模块

  • IService
  • ServiceImpl
  • UI

调用流程

  1. IService-> ServiceImpl
  2. UI层通过注入赋值得到IService实例
  3. 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(),从而导致依赖了底层的具体实现,会有如下缺点:

  1. 依赖了底层的具体实现,违反了依赖倒置原则
  2. 需要多次new一个ServiceImpl对象,浪费资源
  3. UI层需要知道如何怎么ServiceImpl的构造参数,依赖哪些对象,从而增加代码复杂度,并产生很多重复代码

可以利用控制反转的思想解决上述缺点

how

两个实现方法:

  1. 依赖注入
  2. Service Locator

依赖注入

Dependency Injection

让IoC容器去new ServiceImpl实例,并通过“注入”的方式赋值给UI层。实现和底层ServiceImpl的解耦

Service Locator

让UI层全部依赖ServiceLocator,由ServiceLocator提供各种ServiceImpl实例,实现和底层ServiceImpl的解耦

一般流程:

  1. ServiceLocator.registerService();
  2. ServiceLocator.getServcie();

public class ServiceManager {

private static final ServiceManager ourInstance = new ServiceManager();
private HashMap<String, BaseService> mServiceHashMap = new HashMap<>();

public static ServiceManager getInstance() {
return ourInstance;
}

private ServiceManager() {
}

public void registerService(String serviceName, BaseService service) {
if (null == serviceName || null == service) {
return;
}

mServiceHashMap.put(serviceName, service);
}

public BaseService getService(String serviceName) {
return mServiceHashMap.get(serviceName);
}
}

疑问?

ServieImpl的new是在ServiceLocator中呢,还是其他地方?还是都可以

依赖注入和Service Locator对比

  1. Service Locator允许你在一个类 中“解决”依赖问题
  2. DI允许你从类外“注入”依赖
  3. 当使用service locator时,每个类都有一个对service locator的依赖