5

我是一个 DI 新手,如果这是错误的方法或愚蠢的问题,请原谅我。

假设我有一个创建/更新订单的表单,并且我知道它需要检索要显示的产品和客户列表。我想传入它正在编辑的 Order 对象,但我也想将 ProductsService 和 CustomersService 作为依赖项注入。

因此,我希望我的 IoC 容器(无论我使用哪个容器)来提供服务,但这取决于调用代码来提供要编辑的 Order 对象。

我是否应该将构造函数声明为将 Order 对象作为第一个参数,然后将 ProductsService 和 CustomersService 声明为,例如:

public OrderForm(Order order, ProductsService prodsSvc, CustomersService custsSvc)

...或者依赖项应该先出现,Order 对象最后,例如:

public OrderForm(ProductsService prodsSvc, CustomersService custsSvc, Order order)

有关系吗?这是否取决于我使用的 IoC 容器?或者,还有更好的方法?

4

4 回答 4

5

马特,您不应该将普通参数与依赖项混合在一起。由于您的对象将在 IoC 容器的内部创建,您将如何指定必要的参数?

混合依赖和普通参数会使你的程序逻辑更加复杂。

在这种情况下,最好声明依赖属性(即从构造函数中删除依赖项)或在 IoC 构造OrderForm并解析它的依赖项后初始化order字段(即从构造函数中删除普通参数)。

您还可以将所有参数声明为依赖项,包括顺序。

于 2008-10-01T05:08:14.423 回答
4

我不同意@aku 的回答。

我认为您正在做的事情很好,还有其他方法或多或少是正确的。例如,人们可能会质疑这个对象是否应该首先依赖于服务。

不管 DI 是什么,我觉得至少在你的脑海中澄清每个对象所拥有的状态类型是有帮助的,例如真实状态(Order)、派生状态(如果有的话)和依赖关系(服务):

http://tech.puredanger.com/2007/09/18/spelunking/

在任何构造函数或方法上,我更喜欢首先传递真实数据,最后传递依赖项或外部内容。所以在你的例子中,我更喜欢第一个。

于 2008-10-01T06:05:17.393 回答
3

我对允许在没有对 Order 实例的必需引用的情况下实例化 OrderForm 实例感到有点不安。一个原因可能是这会阻止我预先检查空订单。还有什么想法吗?

我想我知道 OrderForm 对象只会由确保在调用 IoC 框架后设置 Order 属性的 Factory 方法来实例化,我会感到欣慰。

于 2008-10-01T05:53:38.683 回答
0

我只是有点晚了,但我建议在这种情况下使用工厂:工厂构造函数将获取*ServiceDI 系统将解析和注入的所需依赖项,而它的Build()方法将接受任何额外的状态参数 - 例如Order. 当然,工厂会在 DI 系统中注册自己,并且可以很好地使用它。

public class OrderFormFactory
{
  private readonly ProductsService _prodsSvc;
  private readonly CustomersService _custsSvc;

  public OrderFormFactory(ProductsService prodsSvc, CustomersService custsSvc)
  {
    _prodsService = prodsService ?? throw new ArgumentNullException(nameof(prodsService));
    _custsSvc = custsSvc ?? throw new ArgumentNullException(nameof(custsSvc));
  }

  public OrderForm Build(Order order)
  {
    // TODO: Any additional logic

    return new OrderForm(_prodsService, _custsSvc, order);
  }
}
于 2020-09-13T09:25:46.530 回答