如何在此课程中使用DI

时间:2014-03-11 20:47:16

标签: dependency-injection ioc-container

我有一个场景,我写了一系列用于从不同来源阅读事件(即支持票证)的类。源1是遗留系统,而Source2是当前系统,源3具有所有事件的数据。

尝试使其更加模块化时,我创建了一个Service类,用作我网站的不可知接口,以便我可以在传入任何事件编号时调用单个方法然后让服务确定从哪个源获取数据。

还有一个#34;装载机"工厂确定使用哪个Source并返回用于从特定来源获取数据的对象。

以下是一些示例代码:

public class IncidentService() : IIncidentService {

   public Incident GetIncident(string incidentId) {
      // ** the bulk of the data comes from one of several (two in this case) sources
      IIncidentLoader loader = IncidentLoaderFactory.GetIncidentLoader(incidentId);

      var incident = loader.GetIncident(incidentId);

      // ** however, there is some data in a 3rd source that applies to all incidents
      var votingSvc = new IncidentVotingService();
      incident.NumberVotes = votingSvc.GetNumberVotes(incidentId);

      return incident;
   }

}

public class IncidentLoaderFactory {

   public static IIncidentLoader GetIncidentLoader(string incidentId) {
      // use regex to check the format of the incident id to determine which source has the data
      if (**format 1**) {
         return new Source1Loader();
      else {
         return new Source2Loader();
      }
   }

}

使用它的方式非常简单......

IIncidentService svc = new IncidentService();
var incident = svc.GetIncident(incidentId);

虽然这种设计在生产中非常有效,但它确实提出了一些问题和问题

  1. 虽然代码没有显示,但我确实需要将Connection Strings传递给不同的服务和加载器。例如,我有以下构造函数

    public IncidentService(string source1ConnectionString, string source2ConnectionString, string source3ConnectionString) {  // do something with the parameters }
    

    显然这不灵活 - (1)如果我想用模拟加载器进行单元测试,以及(2)我需要添加更多加载器怎么办

  2. DI模式表示传递接口参数的实例对象,但在这种情况下,服务使用工厂类来获取加载器。然后工厂类使用正则表达式来确定要返回的加载程序。和以前一样,这不适用于任何类型的隔离单元测试。 (我只能针对真实来源测试事件服务。)

  3. 关于如何调整此单元测试和DI友好的任何想法?一种想法是删除装载机工厂,而是允许使用服务本身注册装载机。然后我可以查询所有加载器以查找给定事件(这些加载器没有托管事件返回null)或者向加载器接口添加一个方法,该方法返回true / false,指示它是否是给定事件id正则表达式格式的正确加载器

1 个答案:

答案 0 :(得分:1)

依赖注入意味着您的服务不应创建IncidentVotingService,也不应具有对IncidentLoaderFactory的硬编码引用。应注入它们,以便在测试期间用模拟对象替换它们。

IncidentService可能如下所示:

public class IncidentService {

    private IIncidentLoaderFactory factory;
    private IIncidentVotingService votingService;

    public IncidentService (IIncidentLoaderFactory factory, IIncidentVotingService votingService){
        this.factory = factory;
        this.votingService = service;
    }

   public Incident GetIncident(string incidentId) {
      // ** the bulk of the data comes from one of several (two in this case) sources
      IIncidentLoader loader = factory.GetIncidentLoader(incidentId);

      var incident = loader.GetIncident(incidentId);

      // ** however, there is some data in a 3rd source that applies to all incidents
      incident.NumberVotes = votingService.GetNumberVotes(incidentId);

      return incident;
   }

}