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

Dependency Injection #89

Open
XXHolic opened this issue Jun 6, 2021 · 0 comments
Open

Dependency Injection #89

XXHolic opened this issue Jun 6, 2021 · 0 comments

Comments

@XXHolic
Copy link
Owner

XXHolic commented Jun 6, 2021

目录

引子

在尝试运用 Scalable Frontend 1 — Architecture Fundamentals 里面所说的 Dependency Injection(依赖注入)时,感觉有些不清不楚,找了些资料,才更明白了一些,在此翻译记录部分聚合。

依赖注入是什么

在软件工程中,依赖注入是一种一个对象接收它所依赖的其它对象的技术。这些其它对象称为依赖。在典型的“使用”关系中,接收对象称为客户端(client),传递的(即“注入的”)对象称为服务(service)。将服务传递给客户端的代码可以是多种类型的东西,称为注入器。注入器告诉客户端要使用什么服务,而不是客户端指定要使用哪个服务。“注入”是指将依赖项(服务)传递到将使用它的对象(客户端)中。

服务是客户端状态的一部分。将服务传递给客户端,而不是让客户端构建或查找服务,是该模式的基本要求。

优势

  • 依赖注入允许客户端灵活地进行配置。只有客户端的行为是固定的。客户端可以对任何支持客户端期望的内在接口的东西进行操作。
  • 依赖注入可用于将系统的配置详细信息外部化到配置文件中,从而允许在不重新编译的情况下重新配置系统。可以针对组件需要不同实现的不同情况编写单独的配置。这包括但不限于测试。
  • 因为依赖注入不需要对代码行为进行任何更改,所以它可以应用于遗留代码的重构。结果就是客户端更加独立,并且更容易使用存根或模拟对象进行单元测试。这种易测试性通常是使用依赖注入时注意到的第一个好处。
  • 依赖注入允许客户端移除具体实现所需要使用的的所有知识。这有助于将客户端与设计更改和缺陷的影响隔离开来。它增强了可重用性、可测试性和可维护性。
  • 减少应用程序对象中的样板代码,因为初始化或设置依赖项的所有工作都由提供程序组件处理。
  • 依赖注入允许并行或独立开发。两个开发人员可以独立开发相互使用的类,而只需要知道类将通过什么接口进行通信。插件通常是由第三方商店开发的,他们甚至从不与开发使用插件的产品的开发人员交流。
  • 依赖项注入减少了类与其依赖项之间的耦合。

劣势

  • 依赖注入创建的客户端需要由构造代码提供配置细节。当明显的默认值可用时,这可能会繁重。
  • 依赖注入会使代码难以跟踪(读取),因为它将行为与构造分离开来。这意味着开发人员必须引用更多的文件来跟踪系统的执行情况。
  • 依赖注入框架是通过反射或动态编程实现的。这会妨碍 IDE 自动化的使用,例如“查找引用”、“显示调用层级”和安全重构。
  • 依赖注入通常需要更多的前期开发工作,因为不能在需要的时间和地点召集某样东西成为正确的东西,但必须要求被注入,并且确保它已被注入。
  • 依赖注入迫使复杂性从类转移到类之间的联系中,可能并不总是理想的或容易管理的。
  • 依赖注入可能助长基于依赖注入框架的依赖。

依赖注入的几种形式

客户端对象至少有三种方式可以接收对外部模块的引用:构造器注入、设置器注入、接口注入。

构造器注入

依赖项是通过客户端的类构器提供的参数传入。

// Constructor
Client(Service service) {
    // Save the reference to the passed-in service inside this client
    this.service = service;
}

当可以首先构造所有依赖项时,最好使用它,因为它可以用来确保客户端对象始终处于有效状态,而不是使其某些依赖项引用为 null(不设置)。但就其本身而言,它缺乏在以后更改其依赖项的灵活性。这可能是使客户端不可变从而实现线程安全的第一步。

// Constructor
Client(Service service, Service otherService) {
    if (service == null) {
        throw new InvalidParameterException("service must not be null");
    }
    if (otherService == null) {
        throw new InvalidParameterException("otherService must not be null");
    }

    // Save the service references inside this client
    this.service = service;
    this.otherService = otherService;
}

设置器注入

这种方式需要客户端提供一个设置器给依赖性。

// Setter method
public void setService(Service service) {
    // Save the reference to the passed-in service inside this client.
    this.service = service;
}

要求客户端为每个依赖项提供设置器。这样就可以随时自由地操作依赖项引用的状态。这提供了灵活性,但是如果要注入多个依赖项,那么客户端很难确保在能够使用之前已注入所有依赖项。

因为这些注入是独立发生的,所以无法判断注入器何时完成了与客户机的连接。依赖项可能仅仅因为调用其设置器失败而保留为 null 。这将强制检查从客户端组装时到使用时的注入是否已完成。

// Set the service to be used by this client
public void setService(Service service) {
    this.service = service;
}

// Set the other service to be used by this client
public void setOtherService(Service otherService) {
    this.otherService = otherService;
}

// Check the service references of this client
private void validateState() {
    if (service == null) {
        throw new IllegalStateException("service must not be null");
    }
    if (otherService == null) {
        throw new IllegalStateException("otherService must not be null");
    }
}

// Method that uses the service references
public void doSomething() {
    validateState();
    service.doYourThing();
    otherService.doYourThing();
}

接口注入

这只是客户端将角色接口发布到客户端依赖项的设置方法。它可以用来确定在注入依赖项时注入器应该如何与客户端对话。

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

// Client class
public class Client implements ServiceSetter {
    // Internal reference to the service used by this client.
    private Service service;

    // Set the service that this client is to use.
    @Override
    public void setService(Service service) {
        this.service = service;
    }
}

接口注入的优点是依赖项可以完全忽略它们的客户端,但是仍然可以接收对新客户端的引用,并使用它,将自身的引用发送回客户端。这样,依赖项就变成了注入器。关键是注入方法(可能只是一个经典的设置器方法)是通过一个接口提供的。

参考资料

🗑️

最近一直在玩《暗黑地牢》,在不看攻略的情况下,还需要花费不少的精力去试错。

84-poster

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

No branches or pull requests

1 participant