当前位置: 首页 > 后端技术 > Node.js

[翻译]DependencyInjection

时间:2023-04-03 23:46:54 Node.js

Introduction在尝试使用ScalableFrontend1—‰ArchitectureFundamentals中提到的DependencyInjection(依赖注入)时,感觉有点不清楚。找了一些资料后,我比较明白了。这里的翻译记录是部分聚合的。来源MyGitHub什么是依赖注入在软件工程中,依赖注入是一种对象接收它所依赖的其他对象的技术。这些其他对象称为依赖项。在典型的“使用”关系中,接收对象称为客户端,传递(即“注入”)对象称为服务。向客户端提供服务的代码可以是多种类型的东西,称为注入器。注入器告诉客户端使用什么服务,而不是客户端指定使用哪个服务。“注入”意味着将依赖项(服务)传递到将使用它的对象(客户端)中。服务是客户端状态的一部分。将服务传递给客户端,而不是让客户端构建或查找服务,是该模式的基本要求。优势依赖注入允许灵活配置客户端。只有客户端的行为是固定的。客户可以对任何支持客户期望的内在接口的东西进行操作。依赖注入可用于将系统的配置详细信息外化到配置文件中,从而无需重新编译即可重新配置系统。可以为组件需要不同实现的不同情况编写单独的配置。这包括但不限于测试。由于依赖注入不需要对代码行为进行任何改变,因此可以应用于遗留代码的重构。结果是客户端更加独立并且更容易使用存根或模拟对象进行单元测试。这种易测试性通常是使用依赖注入时注意到的第一个好处。依赖注入允许客户删除关于具体实现需要使用什么的所有知识。这有助于将客户与设计更改和缺陷的影响隔离开来。它增强了可重用性、可测试性和可维护性。减少应用程序对象中的样板代码,因为所有初始化或设置依赖项的工作都由提供程序组件处理。依赖注入允许并行或独立开发。两个开发者可以独立开发相互使用的类,只需要知道类通过什么接口进行通信即可。插件通常由第三方商店开发,他们甚至从不与制造使用插件的产品的开发人员交谈。依赖注入减少了类与其依赖项之间的耦合。缺点通过依赖注入创建的客户端需要构造代码提供配置细节。当明显的默认值可用时,这可能很繁重。依赖注入会使代码更难理解(阅读),因为它将行为与构造分开。这意味着开发人员必须参考更多文件来跟踪系统的运行情况。依赖注入框架是通过反射或动态编程实现的。这会阻止使用IDE自动化,例如“查找引用”、“显示调用层次结构”和安全重构。依赖注入通常需要更多的前期开发工作,因为无法在需要的时间和地点调用某些东西是正确的,但必须要求注入,并确保它是正确的。依赖注入将复杂性从类中强加到类之间的连接中,这可能并不总是令人满意或易于管理。依赖注入可以促进基于依赖注入框架的依赖。依赖注入的几种形式客户端对象接收对外部模块的引用至少有三种方式:构造函数注入、setter注入和接口注入。构造函数注入依赖项作为客户端类构造函数提供的参数传入。//ConstructorClient(Serviceservice){//在这个客户端中保存对传入服务的引用this.service=service;}这最好在可以先构建所有依赖项时使用,因为它可以用来确保client端对象始终处于有效状态,而不是使其某些依赖项引用为null(未设置)。但就其本身而言,它缺乏以后更改其依赖项的灵活性。这可能是使客户端不可变并因此线程安全的第一步。//ConstructorClient(Serviceservice,ServiceotherService){if(service==null){thrownewInvalidParameterException("servicemustnotbenull");}if(otherService==null){thrownewInvalidParameterException("otherService不能为null");}//在这个客户端中保存服务引用this.service=service;this.otherService=otherService;}Setter注入需要客户端提供依赖的setter。//Setter方法publicvoidsetService(Serviceservice){//在这个客户端中保存对传入服务的引用。this.service=service;}客户端需要为每个依赖项提供设置器。这允许随时自由操作依赖项引用的状态。这提供了灵活性,但是如果要注入多个依赖项,客户端可能很难确保在能够使用它们之前注入所有依赖项。因为这些注入是独立发生的,所以无法判断注入器何时完成与客户端的连接。一个依赖项可能仍然是空的,因为调用它的setter失败了。这将强制检查注入是否从客户端组装时间到消费时间完成。//设置此客户端使用的服务publicvoidsetService(Serviceservice){this.service=service;}//设置此客户端使用的其他服务publicvoidsetOtherService(ServiceotherService){this.otherService=otherService;}//检查此客户端的服务引用privatevoidvalidateState(){if(service==null){thrownewIllegalStateException("servicemustnotbenull");}if(otherService==null){thrownewIllegalStateException("otherService不能为null");}}//使用服务引用的方法publicvoiddoSomething(){validateState();服务.doYourThing();otherService.doYourThing();}接口注入这只是客户端发布角色接口给客户端依赖的setter方法。它可用于确定注入器在注入依赖项时应如何与客户端通信。//Servicesetterinterface.publicinterfaceServiceSetter{publicvoidsetService(Serviceservice);}//客户端类publicclassClientimplementsServiceSetter{//对此客户端使用的服务的内部引用。私人服务;//设置此客户端要使用的服务。@OverridepublicvoidsetService(Serviceservice){this.service=service;}}接口注入的优点是依赖项可以完全忽略它们的客户端,但仍然接收对新客户端的引用,并使用它,将对自身的引用发送回客户端。这样,依赖就变成了注入器。关键是注入的??方法(可能只是一个经典的setter方法)是通过接口提供的。参考依赖注入