依赖注入

2020-06-06  本文已影响0人  陈林峰LeonChen1024

概述

依赖注入(Denpendecy Injection ,DI) 通常和 控制反转(Inverse of Control,IoC) 一起出现.它是实现IoC的主要手段之一.通过依赖注入类可以不关心自身的依赖应该如何构造,而是由注入器代理这个职责,将类需要的依赖构建好后注入到类里.可以达到分离关注点,分离调用方和依赖,提高可复用性和可维护性.

为什么需要依赖注入

为什么需要依赖注入呢? 这和为什么需要IoC的原因基本相同.

在常规的开发过程中,很多时候一个类都是要依赖于其他的类才能实现某些功能,才能够更好的将关注点分离,比如一个车 Car 类 内部需要使用燃油引擎 Engine 类,那么他需要在 Car 的内部做类似 new Engine() 这样的操作, 看起来没有任何的问题,但是当需要更换引擎为他的子类电气引擎ElectricEngine 的时候,问题就来了,我们需要在 Car 的内部修改 Engine 类,或者是当 Engine 做了修改需要额外的参数的时候,也会需要改动到 Car 的内部,并且每个类都得对自身的依赖有更多的了解,这就违反了底米特原则(todo) 和 开闭原则(todo)导致了代码的耦合度极高,不利于维护和扩展.

如图

image

这个时候我们将这个依赖创建获得的权利交给外部去维护,那么这个类只需要声明他需要一个 Engine 即可,至于是燃油还是电气的引擎就由外部控制,此时依赖不再是内部生成,而是通过外部注入得到,再碰到这样的问题的时候,就不需要更改 Car 内部的代码了.而是由外部代码控制即可.

如图

image

依赖注入尾为我们解决了以下问题:

细节

组成结构

依赖注入将依赖的创建和依赖的行为隔离开,这使得程序变得更加松耦合并且更加符合依赖反转原则(todo)和单一职责原则(todo).

最完全的依赖注入包含以下几个部分

UML图如下:

在这里插入图片描述

用前面的汽车的例子对应

常见的简化是直接使用了父子类来替代接口进行操作,这个需要根据情况具体分析.当然,这么做势必会违反依赖倒置原则和影响解耦程度.所以最优的情况是按照要求完整的实现它.

客户端不应该知道具体的依赖实现,而是只关心接口,而接口后面的变化则不会对客户端产生任何影响.

注入器通常也有很多别的名称,比如 提供者,容器,工厂等

实现方式

依赖注入有如下实现方式:

一般情况下使用 自动注入,注解注入的情况比较多.

目前比如 Spring,Guice,Dagger 等框架都实现了依赖注入的功能.

代码示例

/** Client without DI */
  public class Client {
    // Internal reference to the service used by this client
    private ServiceImpl service;

    Client() {
      // Specify a specific implementation in the constructor instead of using dependency injection
      service = new ServiceImpl();
    }

    public void doSth() {
      service.doSth();
    }
  }
/** Client with interface DI */
  public class Client implements ServiceSetter {
    // Internal reference to the service used by this client
    private Service service;

    Client() {}

    public void doSth() {
      service.doSth();
    }

    @Override
    public void setService(Service service) {
      this.service = service;
    }
  }

  /** Service setter interface. */
  public interface ServiceSetter {
    void setService(Service service);
  }

/** Client with setter DI */
public class Client {
  // Internal reference to the service used by this client
  private Service service;

  Client() {}

  public void doSth() {
    service.doSth();
  }

    /**
    * set dependency in .
    */
  public void setService(Service service) {
    this.service = service;
  }
}
/** Client with constructor DI */
public class Client {
  // Internal reference to the service used by this client
  private Service service;

  // set dependency with constructor
  Client(Service service) {
    this.service = service;
  }

  public void doSth() {
    service.doSth();
  }
}
/** Client with annotation DI */
public class Client {
  // Internal reference to the service used by this client
  @Inject
  private Service service;

  Client() {}

  public void doSth() {
    service.doSth();
  }
}

优点

缺点

About Me

我的博客 leonchen1024.com

我的 GitHub https://github.com/LeonChen1024

微信公众号

在这里插入图片描述
上一篇 下一篇

猜你喜欢

热点阅读