依赖注入

杀马特。学长 韩版系。学妹 提交于 2020-03-08 09:01:12

  依赖注入(Dependency Injection),是这样一个过程:由于某客户类只依赖于服务类的一个接口,而不依赖于具体服务类,所以客户类只定义一个注入点。在程序运行过程中,客户类不直接实例化具体服务类实例,而是客户类的运行上下文环境或专门组件负责实例化服务类,然后将其注入到客户类中,保证客户类的正常运行。

一、依赖注入的类别

1.1 Setter注入

  Setter注入(Setter Injection)是指在客户类中,设置一个服务类接口类型的数据成员,并设置一个Set方法作为注入点,这个Set方法接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。

public interface IServiceClass
{
  String ServiceInfo();
}

 

public class ServiceClassA : IServiceClass
{
  public String ServiceInfo()
  {
    return "服务类A";
  }
}

public class ServiceClassB : IServiceClass
{
  public String ServiceInfo()
  {
    return "服务类B";
  }
}

public class ClientClass
{
  private IServiceClass _serviceImp;
  public void Set_ServiceImp(IServiceClass serviceImp)
  {
    this._serviceImp = serviceImp;
  }

  public void ShowInfo()
  {
    Console.WriteLine(_serviceImp.ServiceInfo());
  }
}

static void Main(string[] args)
{
  IServiceClass serviceA = new ServiceClassA();
  IServiceClass serviceB = new ServiceClassB();
  ClientClass client = new ClientClass();

  client.Set_ServiceImp(serviceA);
  client.ShowInfo();
  client.Set_ServiceImp(serviceB);
  client.ShowInfo();
  Console.ReadKey();

}

1.2 构造注入

  构造注入(Constructor Injection)是指在客户类中,设置一个服务类接口类型的数据成员,并以构造函数为注入点,这个构造函数接受一个具体的服务类实例为参数,并将它赋给服务类接口类型的数据成员。

仅ClientClass 和 Content 有变化

public class ClientClass
{
  private IServiceClass _serviceImp;

  public ClientClass (IServiceClass serviceImp)

  {
    this._serviceImp = serviceImp;
  }

  public void ShowInfo()
  {
    Console.WriteLine(_serviceImp.ServiceInfo());
  }
}

 

static void Main(string[] args)
{
  IServiceClass serviceA = new ServiceClassA();
  IServiceClass serviceB = new ServiceClassB();

  ClientClass clientA = new ClientClass(serviceA);
  clientA.ShowInfo();
  ClientClass clientB = new ClientClass(serviceB);
  clientB.ShowInfo();
  Console.ReadKey();

}

1.3 依赖获取

  依赖获取(Dependency Locate)是指在系统中提供一个获取点,客户类仍然依赖服务类的接口。当客户类需要服务类时,从获取点主动取得指定的服务类,具体的服务类类型由获取点的配置决定。

 

二、 反射与依赖注入

  回想上面Dependency Locate的例子,我们虽然使用了多态性和Abstract Factory,但对OCP贯彻的不够彻底。在理解这点前,朋友们一定要注意潜在扩展在哪里,潜在会出现扩展的地方是“新的组件系列”而不是“组件种类”,也就是说,这里我们假设组件就三种,不会增加新的组件,但可能出现新的外观系列,如需要加一套Ubuntu风格的组件,我们可以新增UbuntuWindow、UbuntuButton、UbuntuTextBox和UbuntuFactory,并分别实现相应接口,这是符合OCP的,因为这是扩展。但我们除了修改配置文件,还要无可避免的修改FactoryContainer,需要加一个分支条件,这个地方破坏了OCP。依赖注入本身是没有能力解决这个问题的,但如果语言支持反射机制(Reflection),则这个问题就迎刃而解。

 

三、多态的活性与依赖注入

3.1 多态性的活性

高活多态性——指在客户类实例运行期间,服务类可能会改变的多态性。

中活多态性——指在客户类实例化后,服务类不会改变,但同一时间内存在的不同实例可能拥有不同类型的服务类。

低活多态性——指在客户类实例化后,服务类不会改变,且同一时间内所有客户类都拥有相同类型的服务类。

3.2 不同活性多态的依赖注入选择

  一般来说,高活多态性适合使用Setter注入。因为Setter注入最灵活,也是唯一允许在同一客户类实例运行期间更改服务类的注入方式。并且这种注入一般由上下文环境通过Setter的参数指定服务类类型,方便灵活,适合频繁变化的高活多态性。

  对于中活多态性,则适合使用Constructor注入。因为Constructor注入也是由上下文环境通过Construtor的参数指定服务类类型,但一点客户类实例化后,就不能进行再次注入,保证了其时间稳定性。

  而对于低活多态性,则适合使用Dependency Locate并配合文件配置进行依赖注入,或Setter、Constructor配合配置文件注入,因为依赖源来自文件,如果要更改服务类,则需要更改配置文件,一则确保了低活多态性的时间和空间稳定性,二是更改配置文件的方式方便于大规模服务类替换。(因为低活多态性一旦改变行为,往往规模很大,如替换整个数据访问层,如果使用Setter和Construtor传参,程序中需要改变的地方不计其数)

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!