DDD - 工厂方法和依赖注入

时间:2009-04-25 11:01:27

标签: design-patterns domain-driven-design

我有点卡在一块设计上。我是DDD的新手,想就如何解决这个问题发表意见。

我有一个货币值对象,需要访问存储库以获取附加数据以使类完成。问题(或设计问题)是新的货币实例只能通过工厂方法创建。

public class Currency
{
  internal Currency() {}

  public string Name { get; set; }

  public static Currency CreateCurrencyFromAlphaCode(string alphaCode)
  {
    Currency cur = new Currency();
    //Needs repository to set name etc
    return cur;
  }

  public static Currency CreateCurrencyFromCountryCode(string countryCode)
  {
    Currency cur = new Currency();
    //Needs repository to set name etc
    return cur;
  }

  public static Currency CreateCurrencyFromCountryName(string countryName)
  {
    Currency cur = new Currency();
    //Needs repository to set name etc
    return cur;
  }

}

我认为如果我需要在构造函数中注入一个存储库,那么它会使工厂方法毫无意义吗?

public class Currency
{
  public Currency(IRepoistory repository)
  {

  }
}

考虑到对存储库的依赖,我应该如何设计这个类 - 我必须在每个工厂方法上设置一个参数来接受存储库吗?

4 个答案:

答案 0 :(得分:3)

为什么不将货币大厦移到货币类之外?我不喜欢这个名字,但你可以试试像CurrencyBuilder这样的东西。它可能看起来像这样:

public class CurrencyBuilder {
  private IRepository repository;

  public CurrencyBuilder() : this(new DefaultRepository()) {
  }

  public CurrencyBuilder(IRepository repository) {
    this.repository = repository;
  }

  public Currency FromCountryCode(string countryCode) {
    string currencyName = repository.GetCurrencyNameByCode(countryCode);
    if (currencyName == null)
      throw new CurrencyCodeException(countryCode + " not found");

    Currency c = new Currency();
    c.Name = currencyName;

    return c;
  }
}

使用此设置,当您调用'new CurrencyBuilder()'时,它将使用您的默认存储库实例。但是,为了进行测试,您可以将模拟存储库传递给构造函数。

希望有所帮助,并坚持下去。对于它的价值,这不是一个很好的例子,DI将帮助很多。因此,如果您对完成此任务感到不满意,请不要马上放弃DI。随着你对它越来越熟悉,它的用处会变得更加明显。

答案 1 :(得分:3)

responded to this on the DDD list你也问过它,但我也会在这里重复我的担忧。

我认为你在这里混淆了工厂和存储库的角色。

您命名的方法,例如CreateCurrencyFromAlphaCode,实际上看起来应该是FindCurrencyByAlphaCode,它们应该存在于存储库中,而不是存储在工厂中。 Factory用于创建持久层中的对象(或者用于从已经从持久层接收的数据中实例化对象)。

此外,您的AlphaCode实际上听起来像是一个身份,因此,如果您确实想继续从持久层中检索货币,那么我建议您的Currency很可能不是值对象,而是一个实体。

在不了解您的域名的情况下,很难知道这是否是正确的设计决策。我倾向于认为duffymo的响应会更好地为您服务,然后您不必担心每次都从数据存储中获取。

答案 2 :(得分:1)

如果不了解您的应用程序的上下文,很难确定如果这稍微偏离目标,请原谅我,但似乎您的设计存在两个潜在问题。

首先,您将依赖项注入到一个类中,该类可能会在您的域层中使用。将依赖关系注入域层或域层的依赖关系通常被视为应用程序中某处设计缺陷的症状。

其次,您的货币对象承担两项责任。首先,它是一种货币(显然),其次是负责货币的创造。

要解决这些问题,您是否可以将工厂方法从货币类中分解为应用程序的“更高”层?如果是这样,您可能会发现一切都变得更容易,因为您可以毫无问题地将存储库依赖项注入工厂。这可能意味着重构您的域层代码,因此您在那里传递“现成的”货币而不是货币代码,国家/地区代码等,但我认为这本身并不是一件坏事。领域层应该关注“货币”,而不一定是“货币代码”。

答案 3 :(得分:0)

如果“存储库”的意思是“关系数据库”,我不确定它应该是您的第一选择。毕竟,number of currency codes是相对静态的。它们不会经常改变,因此我不认为您每次创建数据库时都必须支付往返数据。

我想知道从数据库或文本文件启动时加载的静态数据结构是否是更有效的选择。它也是一个较少的依赖。