Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

控制反转和依赖注入 #39

Open
dark9wesley opened this issue Jan 11, 2024 · 0 comments
Open

控制反转和依赖注入 #39

dark9wesley opened this issue Jan 11, 2024 · 0 comments

Comments

@dark9wesley
Copy link
Owner

dark9wesley commented Jan 11, 2024

控制反转和依赖注入

  1. 控制反转(IoC): 在传统的编程中,应用程序通常会控制自己的流程,并且自己负责创建和管理对象。而控制反转就是将这种控制的权力反转,让外部框架或容器来控制应用程序中各种组件的创建和管理。简而言之,不再由你的代码掌握一切,而是由外部的框架或容器掌握。

  2. 依赖注入(DI): 依赖注入是一种实现 IoC 的方式,它通过将一个对象需要的依赖关系从外部注入(传递)到该对象中。这样,对象不再负责自己的依赖,而是由外部负责将依赖注入给对象。

简而言之,控制反转是一种思想,它让应用程序的控制权力反转到外部;而依赖注入是实现控制反转的一种具体方式,它通过注入对象的依赖关系来减轻对象对其他对象的控制。这两个概念通常一起使用,以实现更灵活、可扩展、可测试的代码结构。

代码示例

先来看一个不使用控制反转的例子。

不使用控制反转和依赖注入

首先我们有两个基础类,Engine类和Skylight类,它们分别代表发动机和天窗。

class Engine {
  constructor(public cylinder: number) {
    console.log(`这是${cylinder}缸的发动机`);
  }

  start() {
    console.log(`${this.cylinder}缸发动机启动`);
  }

  stop() {
    console.log(`${this.cylinder}缸发动机启动`);
  }
}

class Skylight {
  constructor(public hasSkylight: boolean) {
    console.log(hasSkylight ? '有天窗' : '无天窗');
  }

  open() {
    if (this.hasSkylight) {
      console.log(`打开天窗`);
    }
  }

  shut() {
    if (this.hasSkylight) {
      console.log(`关闭天窗`);
    }
  }
}

然后我们有个基于这两个基础类的Car类,它需要Engine和Skylight两个实例。

class Car {
  public Engine: Engine;
  public Skylight: Skylight;

  constructor(
    cylinder: number,
    hasSkylight: boolean,
  ) {
    this.Engine = new Engine(cylinder);
    this.Skylight = new Skylight(hasSkylight);
  }
  run() {
    this.engine.start();
    this.skylight.open();
    console.log('汽车开始行驶');
  }
  stop() {
    this.engine.stop();
    this.skylight.shut();
    console.log('汽车停止行驶');
  }
}

最后我们创建一个Car实例,并调用run方法,可以看到控制台输出。

const car = new Car(4, true);
car.run();

控制台输出:

4缸的发动机
有天窗
汽车开始行驶

可以看到,这个例子中,Car类负责控制Engine和Skylight两个实例的创建,并且需要知道它们的构造函数需要什么参数。

假如以后Engine或Skylight这两个基础类的入参需要增多时,Car类需要跟着修改,这显然不是我们想要的,耦合太重了。

下面看一下如何使用控制反转和依赖注入来解决这个问题。

使用控制反转和依赖注入

还是使用上面那两个基础类,修改一下Car类的代码

class Car {
  constructor(
    public Engine: Engine,
    public Skylight: Skylight,
  ) {}

  run() {
    this.engine.start();
    this.skylight.open();
    console.log('汽车开始行驶');
  }
  stop() {
    this.engine.stop();
    this.skylight.shut();
    console.log('汽车停止行驶');
  }
}

可以看到,Car类不再负责Engine和Skylight的创建,而是接受这两个类的实例。

当外部想创建Car类时,需要先将这两个依赖注入到Car类中。

这就是所谓的依赖注入。

const fourEngine = new Engine(4);
const hasSkyLight = new Skylight(true);

const car = new Car(fourEngine, hasSkyLight);
car.run();

这么做的好处是,当后续Engine类或Skylight类的发生变化时,不再需要修改Car类,只需要修改这两个类和创建的地方即可。

也就是说,Car类将控制创建Engine类或Skylight类的权力交了出去,由外部容器创建,这就是所谓的控制反转。

这个外部容器,也称之为控制反转容器(IoC容器)。

参考

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant