【问题标题】:Dependecy injection of arguments known at runtime?运行时已知的参数的依赖注入?
【发布时间】:2011-02-12 06:50:28
【问题描述】:

我使用 IoC 容器已经有一段时间了,但今天我发现代码中一遍又一遍地出现了一些“模式”。为了给您一些背景知识,我现在正在研究主要用于数据分析的 Web 应用程序。那里有一组功能,要求用户在一开始就选择我们所说的QueryTypeContex。选择此查询类型后,可能会采取其他步骤,但所有步骤均在此特定QueryTypeContex 中执行。在 gui 中,QueryTypeContex 拾取表示为使用其他控件打开新选项卡。

当用户使用给定的QueryTypeContex 工作时,对服务器的所有ajax 调用都包括QueryTypeId,它标识用户的选择并用于在服务器上构建QueryTypeContex,然后用于各种数据检索和操作。

我发现,我们使用 Ioc 容器构建的许多控制器(我们使用 asp.net mvc)都有一个共同点。有一个动作方法看起来有点像这样:

public class AttributeController : Controller 
{
  public AttributeController(IUsefulService usefulService)
  {
     _usefulservice = usefulService;
  }
  ActionResult GetAttributes(QueryTypeContex context)
  {
    var dataDto = _usefulService.Manipulate(context, currentUser);
    return JSon(dataDto);
  }
  ...
}

为了将QueryTypeContex 绑定到动作参数,我们使用自定义模型绑定器从数据库中提取一些信息。一旦服务获得QueryTypeContex 作为参数,它会将其或其属性传递给实例数据访问层的方法参数中的协作者。于是就有了一个像这样的工厂类

public interface IDateValueFactory 
{
   DateValue CurrentYear(QueryTypeContex context);
   DateValue RollingMonth(int numberOfMonths, QueryTypeContex context);
   DateValue RollingQuareter(int numberOfQuarters, QueryTypeContex context);
}

public class DateValueFactory : IDateValueFactory 
{
  public DateValueFactory(IDateValueDb dateValueDb)
  {
    _dateValueDb = dateValueDb;
  }

  public DateValue CurrentYear(QueryTypeContext context)
  {
    var currentYear = _dateValueDb.GetCurrentYear(context.Id);
    return new DateValue(DateValueType.CurrentYear, currentYear, context);
  }

  public DateValue RollingMonth(int numberOfMonths, QueryTypeContex context)
  {
    return new DateValue(DateValueType.RollingMonth, numberOfMonths, context);
  }
  ...

}

正如您所见,所有这些方法都将QueryTypeContex 作为参数,更重要的是它们在短暂的生命周期中都获得了完全相同的QueryTypeContex 实例(一个网络请求)。所以我开始怀疑我是否可以重构它,以便每当许多服务类方法需要QueryTypeContex 作为参数时,它将通过构造函数注入,而不是再次传递相同的值。例如:

public interface IDateValueFactory 
{
   DateValue CurrentYear();
   DateValue RollingMonth(int numberOfMonths);
   DateValue RollingQuareter(int numberOfQuarters);
}

public class DateValueFactory : IDateValueFactory 
{
  public DateValueFactory(IDateValueDb dateValueDb, QueryTypeContext context)
  {
    _dateValueDb = dateValueDb;
    _context = context;
  }

  public DateValue CurrentYear()
  {
    var currentYear = _dateValueDb.GetCurrentYear(_context.Id);
    return new DateValue(DateValueType.CurrentYear, currentYear, _context);
  }

  public DateValue RollingMonth(int numberOfMonths)
  {
    return new DateValue(DateValueType.RollingMonth, numberOfMonths, _context);
  }
  ...

}

现在真正的问题是: 这是一个好主意,还是违反了我应该遵守的一些设计原则?

为了注入 QueryTypeContex 实例,使用来自 http 请求的信息构建,我考虑将 QueryTypeId 嵌入到 uri 中,以便它可以在服务器上的 RouteData 中使用。然后在构建控制器之前,我可以将其拉出,构建QueryTypeContex,为该请求创建嵌套的 IoC 容器并将其注入容器中。然后,每当某个类需要QueryTypeContex 来执行其工作时,它就会简单地将其声明为构造函数参数。

【问题讨论】:

  • 您阅读指南了吗?
  • @PhoenixFF 哪个向导?

标签: asp.net-mvc-2 dependency-injection ioc-container


【解决方案1】:

任何你可以有意义地作为依赖推送给构造函数的东西,你都应该这样做。与构造函数注入关联的依赖项是实现细节,而方法参数是模型的 API 的一部分。

重构通过构造函数连接的依赖项比更改 API 容易得多,因此出于可维护性的原因,您应该更喜欢尽可能少的方法参数。

【讨论】:

  • 嗯,在这种情况下,根据给出的示例,我可能会在方法中保留上下文传递。否则,实现会假设它的配置方式(即它的生命周期)。此外,如何通过某种 BuildUp 方法通过容器将上下文提供给构造函数?看起来像一个抽象工厂,将上下文传递给 Create() 方法会更有意义吗? (要明确:我不是在争论你的回答,因为我自己也在努力解决这个问题)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-09
  • 2012-11-23
相关资源
最近更新 更多