依赖注入
问题:
Open-Closed Principle原则讲的是:一个软件实体应当对扩展开放,对修改关闭。将变化隔离,使得变化部分发生变化时,不变部分不受影响。
为了做到这一点,要利用面向对象中的多态性,使用多态性后,客户类不再直接依赖服务类,而是依赖一个抽象的接口。这样,客户类就不能在类的内部直接实例化具体的服务类。但是客户类在运作中又客观需要具体的服务类提供服务,因为接口并不能提供实质性的服务。这样一来就产生了“客户类依赖接口,接口不能提供实质的服务” 和“客户类需要具体实质的服务类”的矛盾。
解决:
依赖注入Dependency Injection。实现过程:由于客户类只能依赖服务的一个接口,而不是依赖具体服务类,所以客户类提供一个注入点。在程序运行过程中,客户类直接实例化具体的服务类实例,而是客户类的运行上下文环境或者专门组件 负责实例化服务类,然后通过客户类提供的注入点 将 实例化的服务类注入,从而确保客户类能正常运行。
Unity应用程序块是一个轻量级、可扩展的依赖注入容器,支持构造函数,属性和方法调用注入。
Unity应用程序块使用容器注册类型和映射的两种方法如下:
1、RegisterType 此方法用容器注册一个类型。在适当的时候,容器将构建一个指定的类型的实例。这可以通过类的特性或者调用Resolve方法时初始化依赖注入。
构建的对象的生命周期与在方法参数中指定的生命周期一致。如果没有指定生命周期的值,将为类型注册一个暂时的生命周期,这意味着容器将为每一个对Resolve的调用创建一个新的实例。
2、RegisterInstance 此方法将一个指定的类型的已存在的实例 注册到 容器,并带有指定的生命周期。容器将在生命周期内返回已有的实例。 如果没有指定生命周期,实例将拥有容器控制的生命周期。
四种注册的实例介绍:
1、类型的配置容器注册
作为RegisterType和Resolve方法的重载的一个示例,下面代码注册了一个用于接口ICustomerService的映射,指定容器将放回CustomerService类的实例。CustomerService实现了ICustomerService接口。
IUnityContainer myContainer = new UnityContainer(); myContainer.RegisterType<ICustomerService, CustomerService>(); ICustomerService customerServiceInstance = myContainer.Resolve<ICustomerService>();
2、已有对象实例的配置容器注册
作为RegisterType和Resolve方法的重载的一个示例,下面代码注册了实现了ICustomerService接口的CustomerService类的一个已有实例,然后获取次实例。
IUnityContainer myContainer = new UnityContainer(); CustomerService customer = new CustomerService(); myContainer.RegisterType<ICustomerService>(customer); ICustomerService customerServiceInstance = myContainer.Resolve<ICustomerService>();
3、构造函数注入
作为构造函数注入的一个示例,如果开发人员用Unity容器的Resolve方法实例化的类(该类有一个构造函数定义了一个或者多个对其他类的依赖),Unity容器将自动创建指定在构造函数参数中的依赖对象的实例。
例如,下列代码展示了依赖于 LoggingService 对象的 CustomerService 类。
public class CustomerService { public CustomerService(LoggingService myServiceInstance) { // work with the dependent instance myServiceInstance.WriteToLog("SomeValue"); } }
在运行时,开发人员使用容器的 Resolve 方法创建了 CustomerService 类的一个实例,这导致了实例生成框架将具体类 LoggingService 的一个实例注入到 CustomerService 类中。
IUnityContainer uContainer = new UnityContainer(); CustomerService myInstance = uContainer.Resolve<CustomerService>();
4、属性注入
除了前面描述的构造函数注入以外,Unity应用程序块还支持属性和方法调用注入。下面代码示例了属性注入。ProductService类暴露了一个引用另一个名为SupplierData类的实例属性。要强制依赖对象的注入,开发人员必须下列代码一样使用Dependency特性装饰属性的声明。
public class ProductService { private SupplierData supplier; [Dependency] public SupplierData SupplierDetails { get { return supplier; } set { supplier = value; } } }