标签:模式 支持 工作 highlight div 维护 注册表 初始化 特定
一、起因
首先说起依赖注入,是为了解决类与类之间关联性太强,耦合度太高。如果一个高级类(A类)中包含另一个低级类(b类),传统方式,是在A类中初始化b类。即:
public class A { private b b1 = new b(); }
这样A类要维护b类的生命周期(创建,销毁)。而且在A类的外部根本看不到其内部的具体依赖对象,无从考究他内在的依赖对象,造成A类处于一个比较复杂的状态。
如果要降低A类与b类的关联性,需要把b类暴露出去,让其他外部成员可以看到A类具体依赖的对象。所以:
public class A { private b b_1; public A(b b1) { b_1 = b1; } }
现在,如果初始化A类的时候,看到其内部具体依赖的对象是b(构造函数创建时需要传入b实例),A类只维护b实例的引用,不负责创建和销毁工作(通过外部进行)。现在还是有些缺陷,就是A类仍然依赖b实例,和b实例还是有着强耦合。b实例有具体的实现,假如更换成抽象,A类与抽象的关联,抽象再与b实例关联(“没有什么事情是加一个中间层解决不了的”)。这样依赖就变成了两个,这怎么变复杂了?本来的一个依赖,变成两个了。虽然是变复杂了,但是A类与b实例的关联关系就变弱了,而且可以随时替换b类(换成c,d...)。
interface ib { } public class b:ib { } public class A { private ib b_1; public A(ib b1) { b_1 = b1; } }
这样就看起来完美了,A类不再依赖b类了,变成基于抽象的编程了。但是外部仍然需要有个初始化的类给我们传入,如果在外部构造一个传入,不同样是把内部的耦合转到外部去了吗,仍然不好。这时候就需要第三方工具帮助我们创建类实例,不能我们自己在代码中都是new。
二、方案
管理实例化和管理对象责任的方法一共有三种:工厂,服务定位器和依赖注入。他们都各有优缺点。
1、工厂模式
public class three { public virtual ib Createb() { return new b(); }
}
现在把b实例创建通过第三方工厂进行创建。只需通过调用第三方方法就可以。不同的抽象实现只需要继承three工厂类修改重写创建方法就行。
2、服务定位模式
使用服务定位器为使用另一个类代表您创建对象的一般方法提供了另一种变体。您可以将服务定位器视为一个注册表,您可以在其中查找应用程序中的另一个类创建并向服务定位器注册的对象或服务的实例。服务定位器可能支持通过字符串键或接口类型查询对象。通常,与工厂模式不同的是,工厂创建对象,但将管理其生存期的责任交给客户机类,服务定位器负责管理对象的生存期,并简单地向客户机返回一个引用。此外,工厂通常负责创建特定类型或类型族的实例,而服务定位器可能能够返回对应用程序中任何类型的对象的引用。使用服务定位器时,每个类都将依赖于您的服务定位器。
3、依赖注入
所有工厂模式和服务定位器模式的一个共同特征是,高级客户机对象仍然负责通过请求所需类型的特定实例来解决其自身的依赖关系。它们各自采用一种复杂程度不同的拉动模型,将各种责任分配给工厂或服务定位器。pull模型还意味着高级客户机类依赖于负责创建或定位它想要使用的对象的类。这也意味着高级客户机类的依赖项隐藏在这些类中,而不是在单个位置指定,这使得它们更难测试。
依赖注入采用相反的方法,采用推模型代替拉模型。控制反转是一个经常用来描述这种推送模型的术语,依赖注入是控制反转技术的一个具体实现。 对于服务定位器,应用程序类通过给定位器的消息显式地请求它。使用注入时,没有显式请求,服务出现在应用程序类中,因此控制反转。(控制容器反转和依赖注入模式。) 使用依赖注入,另一个类负责在运行时将依赖注入(推送)到高级客户机类中。
如果采用依赖项注入方法,应用程序中会有许多类需要其他类或组件将必要的依赖项作为参数或属性值传递到它们的构造函数或方法中,然后才能使用它们。这意味着您的应用程序需要一个类或组件,该类或组件负责实例化所有必需的对象,并将它们传递到正确的构造函数、方法和属性中:您的应用程序在执行任何工作之前必须知道如何组合其对象图。这必须在应用程序生命周期的早期发生。
标签:模式 支持 工作 highlight div 维护 注册表 初始化 特定
原文地址:https://www.cnblogs.com/wangjj20180701/p/14964358.html