依赖注入与Service Locator

  • 为什么需要依赖注入?
    • 普通的ServiceUser来负责直接创建所需Service实现的实例方法.拥有以下的局限
      • 在不同的环境下,ServiceProvider是千差万别的(数据库,临时文件,内存).
      • 所以,不能将ServiceUser作为组件发布(适应不了各种差异环境).
    • 为了将ServiceUser所在单元作为组件发布,必须满足以下的条件.
      • 将ServiceUser与具体的ServiceProvider_Imp解耦(解除编译时依赖).即不能出现new ServiceProvider_Imp()语句.
      • 在运行时,根据环境来为ServiceUser来动态地提供ServiceProvider的实现实例.
      • 总之,将ServiceUser和ServiceProvider之间的依赖,由编译时,推迟到运行时动态决定.
      • 即在运行时"注入"这种依赖,称为依赖注入(DI).
      • ServiceUser可以看做框架.其需要对外发布,被其他模块使用.
      • ServiceProvider可看做插件.其在不同的环境下有差别.
    • 依赖注入
      • 在编译时,使用IServiceProvider接口.在运行时,再将具体的实现类型绑定到ServiceUser上.
      • 从而实现了服务的使用者(框架)和服务的提供者(插件)的松耦合.
    • 加入一个Assembler(容器)来完成对框架单独发布所需的要求.
  • 构造器DI
    • 构造器指的是ServiceUser的构造器,也就是在构造ServiceUser的实例时,才把具体的ServiceProvider_实现传递给它.
    •  1  class ServiceUser
       2     {
       3         IServiceProvider sp;
       4         ServiceUser(IServiceProver sp)
       5         {
       6             this.sp = sp;
       7         }
       8     }
       9
      10     private MutablePicoContainer configureContainer() {
      11         MutablePicoContainer pico = new DefaultPicoContainer();
      12         //下面就是把ServiceProvider和ServiceUser都放入容器的过程,以后就由容器来提供ServiceUser的已完成依赖注入实例,
      13         //其中用到的实例参数和类型参数一般是从配置档中读取的,这里是个简单的写法。
      14         Parameter[] finderParams =  {new ConstantParameter("movies1.txt")};
      15         pico.registerComponentImplementation(IServiceProvider.class, ServiceProvider.class, finderParams);
      16         pico.registerComponentImplementation(ServiceUser.class);
      17         //至此,容器里面装入了两个类型,其中没给出构造参数的那一个(ServiceUser)将依靠其在构造器中定义的传入参数类型,在容器中
      18         //进行查找,找到一个类型匹配项即可进行构造初始化。
      19         return pico;
      20     }

      CtorDI

    • 依赖被延迟到容器的构造过程中.
    • 容器本身(具体来说是其构造过程)对ServiceUser和ServiceProvider都有依赖.
    • 所以,ServiceUser,ServiceProvider,容器三者,没有任何的依赖关系.
    • 所有的依赖关系,所有的变化,都被封装到了容器的构造中.
    • 实例项目中,可以使用配置文件来将变化排斥到编译期外.
    • 容器含有一个类似GetInstance(Type t)的方法,在该方法中,容器调用ServiceUser的构造器,而使用的参数是在容器添加ServiceProvider时指定的(也就能够在不同的环境下,使用不同的ServiceProvider的实现).
  • 属性DI
    • 其与构造器DI的差别

      • 在获取对象实例时(GetInstance方法),前者通过反射得到待创建类型(ServiceUser)的构造器信息,然后根据构造器的参数类型(ServiceProvider)在容器中进行查找,然后构造出合适的实例.
      • 而属性DI是通过反射得到待创建类型的所有属性,然后根据属性的类型在容器中查找对应类型的实例.
      • 这种方式利于使用XML配置的方式来实现,所以诸如Spring的框架使用的都是这种方式.
  • 接口DI
    • 首先,在接口中定义需要注入的信息.
    • 然后,在ServiceUser中实现该接口.
    • 最后,由容器调用接口定义的注入方法来完成注入.
  • Service Locator
    • 基本思想:有一个对象(服务定位器)知道如何获取一个应用程序所需的所有服务(对象).
    • 与DI的区别
      • ServiceUser必须显示调用Service Locator的方法来获取对应的服务对象(ServiceProvider)实例.
      • 而在DI中,这个过程是由容器隐式完成的.
    • 由于ServiceUser和Servive Locator之间的依赖性,降低了模块之间的独立性,所以IOC框架大多使用的是DI.
    • 而Locator的优势是实现简单,所以当开发工作不复杂时,可以使用Service Locator.
  • DI和Locator的对比
    • 首先,两者的目的都是解耦ServiceUser和ServiceProvider的实现.
    • 核心区别在于,ServiceProvider的实现,以什么方式提供给ServiceUser.
      • 在Locator中,ServiceUser直接发送方法调用来请求具体的ServiceProvider实现的实例.
      • 在DI中,ServiceUser不再需要任何的调用,由容器来隐式地完成将ServiceProvider的实现实例注入到ServiceUser中的过程.
    • 控制反转(IOC)是框架的基本特征.
      • 增加了框架代码的理解难度,同时增加了调试难度.
    • 在选择两者的取舍时,主要考虑的是(ServiceUser)对Locator的依赖会不会造成问题.
      • 首先,取决于ServiceUser的性质,如果有多个ServiceUser要使用同一服务,那么可以使用Locator.
      • 而如果要将ServiceUser作为组件发布供别人使用,而别人的Locator是不可预测的,很可能带来不兼容问题,所以要使用DI.
      • 另一方面, 在DI中,容器和ServiceProvider的实现没有依赖关系.除了配置文件信息,服务实现无法获取更多的关于容器的信息.
    • 使用DI模式,可以更清晰地理清组件间的依赖关系.
      • 只需要观察依赖注入机制(例如构造函数).就可以看到整个的依赖关系.
    • 而使用Locator模式,必须在源代码中搜索所有对Locator的调用才可以.
    • 测试
      • 部分人会认为DI简化了测试,因为可以非常简单地在真实和伪组件(ServiceProvider的实现)之间切换.
      • 但是,良好的Locator实现,应该能做到很容易地替换掉Locator.
      • 也就是说,良好的架构应该支持简单地使用一个伪组件来替换掉一个真实组件,来方便地进行测试.
      • 所以,如果ServiceProvider的实现如果要脱离自己的控制,在另一个环境中使用,那么就不能对Locator做任何的假定.
  • 构造DI对比属性DI
    • 基准:应该在那里填充字段(属性)的值?构造函数还是设置方法?
    • 构造函数的一个好处是隐藏不可变的字段.
      • 在构造器内将其设置,然后不提供Setter即可.
    • 构造DI的问题
      • 参数个数过多
      • 参数多是无法描述信息的简单类型.
      • 对象含有多个构造函数,且有继承关系.
  • 代码配置对比配置文件
    • 在简单的应用中,直接使用代码来完成配置.
    • 当配置文件变得越发复杂时,使用一种编程语言来编写配置文件.
  • 分离配置和使用
    • 关键:服务的配置和使用应该被分离开.
    • 实际上,这反映了一个基本的设计原则:分离接口与实现.
    • 在面向对象的程序中,我们在一个地方根据条件来决定具体实例化哪一个子类,之后使用多态(接口类型)来操作该类型.
  • DI的目的
    • 用来降低主程序与对象间的关联.
    • 同时也能减低对象间的关联.
    • 简化对象的建立动作,进而让对象更加容易使用.

依赖注入与Service Locator

时间: 2024-10-05 21:44:21

依赖注入与Service Locator的相关文章

dotnet core在Task中使用依赖注入的Service/EFContext

C#:在Task中使用依赖注入的Service/EFContext dotnet core时代,依赖注入基本已经成为标配了,这就不多说了. 前几天在做某个功能的时候遇到在Task中使用EF DbContext的问题,学艺不精的我被困扰了不短的一段时间, 于是有了这个文章. 先说一下代码结构和场景. 首先有一个HouseDbContext,代码大概是下面这样: public class HouseDbContext : DbContext { public HouseDbContext(DbCon

[ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式

原文:[ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式 IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架之中以实现对流程的复用,并按照"好莱坞法则"实现应用程序的代码与框架之间的交互.我们可以采用若干设计模式以不同的方式实现IoC,比如我们在前面介绍的模板方法.工厂方法和抽象工厂,接下来我们介绍一种更有价值的IoC模式:依赖注入(DI:Dependency Injection). 一.由容器提供对象 和前面介绍的工厂方法和抽象工厂模式一样,依

依赖注入和依赖注入容器

http://www.digpage.com/di.html#di 为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Service Locator)两种模式. 关于依赖注入与服务定位器, Inversion of Control Containers and the Dependency Injection pattern 给出了很详细的讲解,这里结合Web应用和Yii具体实现

yii依赖注入

为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Service Locator)两种模式. 关于依赖注入与服务定位器, Inversion of Control Containers and the Dependency Injection pattern 给出了很详细的讲解,这里结合Web应用和Yii具体实现进行探讨,以加深印象和理解. 这些设计模式对于提高自身的设计水平很有

用Decorator实现依赖注入,像Java一样写后台

最近闲来无事,突发奇想,也顺便练练手,于是就萌生了,能否用typescript的decorator写一个Nodejs SpringMVC,通过依赖注入,自动实现文件加载,实例化等.然后就有了这个项目. 该项目支持: 依赖注入Controller ,Service 注入GET/POST/PUT/DELETE/PATCH等rest方法 解析rest api的参数,例如RequestParam 上传文件支持Multer 支持在vscode里面直接debug typescript 的代码 想学习如何de

跟我学AngularJs:Service、Factory、Provider依赖注入使用与区别

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka        本教程使用AngularJs版本:1.5.3        AngularJs GitHub: https://github.com/angular/angular.js/        AngularJs下载地址:https://angularjs.org/ 用有过Spring的人都知道,Spring的核心思想就是DI(依赖注入,Dependency Injection)和I

Catel帮助手册-Catel.Core:(5)依赖注入(ServiceLocator and TypeFactory)

1,简介 在Catel2.0之前,IOC容器内部使用的是Unity,然而,这就强制所有的用户在他的应用程序中使用Unity作为IOC容器,也需要这样划分库,从2.0以后,一个不同的技术被使用了,这个允许开发者可以使用他们自己悬着的IOC容器技术. 1.1在Ioc中不同的组件 在Catel中有许多不同的组件他们对于Ioc是非常重要的. ServiceLocator 该组件用于注册所有的类型,这个事真正的Ioc容器 TypeFactory 用于创建类型的组件,使用IServiceLocator来获取

[Architect] ABP(现代ASP.NET样板开发框架)(7) 依赖注入

本节目录: 什么是依赖 传统方式的问题 解决方案 构造函数注入 属性注入 注入框架 Abp依赖注入框架 注册 通常注册 帮助接口 自定义注册 解析 构造函数 & 属性注入 IIocResolver & IIocManager 扩展 IShouldInitialize ASP.NET MVC & ASP.NET Web API注入 什么是依赖 如果你已经知道依赖注入思想,构造函数和属性注入模式,你可以跳到下节. 维基:"依赖注入是1种软件设计模式,在这种模式下,1个或多个依

ASPNET5 依赖注入(Dependency Injection)

依赖注入一直是asp.net web框架(Web API,SignalR and MVC)中不可或缺的一部分,但是在以前,这个框架都是各自升级,都有各自的依赖注入实现方式,即使Katana项目想通过Owin将这些项目连接起来,你还是要做统一的容器去支持它们,现在事情有所变化了. 抽象 asp.net团队决定提供依赖注入功能通过提炼最流行的IOC容器中最核心的功能,然后让不同的组件实现这些接口来实现依赖注入. IServiceProvider 这个最主要的接口,开发都可以通过这个接口去检索Ioc容