我的DDD工厂类应该采用哪些方法?

时间:2009-03-04 15:06:11

标签: c# design-patterns dns domain-driven-design factory

我正在努力了解我的工厂类应该在我的DDD项目中做什么。是的,工厂应该用于创建对象,但究竟应该做什么。请考虑以下工厂类:

    public class ProductFactory
    {
        private static IProductRepository _repository;

        public static Product CreateProduct()
        {
            return new Product();
        }

        public static Product CreateProduct()
        {
            //What else would go here?
        }

        public static Product GetProductById(int productId)
        {
            //Should i be making a direct call to the respoitory from here? 
            Greener.Domain.Product.Product p = _repository.GetProductById(productId);
            return p;
        }
    }

我应该从工厂内直接调用存储库吗?

在从数据库中检索数据时,如何管理对象创建?

我需要做什么才能完成这个课程,我还应该使用其他什么方法?

我是否应该使用此类从域和存储库中创建Product对象?

请帮忙!

7 个答案:

答案 0 :(得分:11)

  

我应该直接打电话给   来自内部的存储库   工厂?

不,在检索物品时不要使用工厂,只在第一次使用工厂时才使用工厂。

  

我应该如何管理对象创建   从数据库中检索数据时?

如果对象的初始创建需要,则将该数据传递到工厂。

  

我需要做什么才能上课   完成,还有其他什么方法   有?

许多工厂甚至不是单独的类,它们只是提供对象创建的方法。如果您觉得它只是调用无参数构造函数,您可以将工厂方法折叠到另一个类中。

  

我应该使用这个类来创建   来自域和的Product对象   从右边的存储库?

存储库用于(在某种意义上创建)现有对象,工厂是第一次创建对象。

最初,除了调用构造函数之外,许多工厂不会做太多工作。但是一旦开始重构和/或创建更大的对象层次结构,工厂就变得更加相关。

解释和示例:

例如,在我正在研究的项目中,我有一个excel处理器基类和许多实现该基类的子类。我使用工厂获取正确的工厂,然后调用它上面的方法,不知道返回了哪个子类。(注意:我更改了一些变量名称,并修改了大量代码)

处理器基类:

public abstract class ExcelProcessor
{
      public abstract Result Process(string ExcelFile);
}

其中一个处理器子类:

public class CompanyAExcelProcessor : ExcelProcessor
{
     public override Result Process(string ExcelFile)
     {
      //cool stuff
     }
}

厂:

 public static ExcelProcessor CreateExcelProcessor(int CompanyId, int CurrentUserId)
 {
      CompanyEnum company = GetCompanyEnum(CompanyId);
      switch (company)
      {
           case CompanyEnum.CompanyA:
                return new CompanyAExcelProcessor();
           case CompanyEnum.CompanyB:
                return new CompanyBExcelProcessor();
           case CompanyEnum.CompanyC:
                return new CompanyCExcelProcessor(CurrentUserId);
           //etc...
      }
 }

用法:

ExcelProcessor processor = CreateExcelProcessor(12, 34);
processor.Process();

答案 1 :(得分:6)

请注意,实例化新对象有两个原因:创建,并从数据库中重新补充

第一种情况由工厂处理。您可以提供多种方法在工厂中创建对象。 工厂方法应返回有效对象,因此您可以将参数传递给这些方法以提供所需信息。

工厂方法也可以根据参数选择实际类型进行实例化。

您不应将此与数据库中的再水化混合使用。这种实例化应该从数据行中获取值并用它实例化对象。我通常称之为数据构建器,而不是工厂

主要区别在于工厂将使用新标识实例化对象,而数据库将实例化具有已存在标识的对象。

答案 2 :(得分:2)

您工厂的创建方法应该是将品牌打击新对象置于VALID状态所必需的。

现在,对于某些对象,这意味着除了这个之外你不会做任何事情:

public Product Create()
{
   return new Product();
}

但是,您可能具有要在创建对象时强制实施的业务规则,默认设置或其他要求。在这种情况下,您可以将该逻辑放在该方法中。

这是工厂利益的一部分。您现在只有一个特殊逻辑所在的位置,并且只有一个创建新对象的位置。

答案 3 :(得分:1)

我个人会在几种情况下使用工厂:

1)其他地方管理这个工厂返回的对象类型(即它可以根据情况返回对象。例如,我在测试时返回一个存根对象,当我没有时返回一个实际的实现(这显然更多)控制/依赖注入反转问题 - 但如果您还不想将容器添加到项目中))。

2)我有非常复杂的对象,它们有容器,依赖关系,其他关系等,需要仔细构建它们以避免创建null或无意义的引用。例如,如果我有一个Schedule对象,我可能需要设置一些开始,结束日期字段 - 如果用于检索的逻辑,计算出这些日期足够复杂,我可能不希望调用类知道它并只调用默认的工厂方法创建了计划对象。

希望这有帮助。

答案 4 :(得分:0)

在上面给出的例子中,我对你的工厂和存储库之间的区别有点不清楚。我想知道你是不是应该简单地将CreateProduct添加为存储库的方法,并使用DI将存储库推送到需要它的代码中?如果工厂正在做等等......

或者,如果您只是希望它作为全球注册的存储库,可能是这样的:

public static IFooRepository Default {get;private set;}
public static void SetRepository(IFooRepository repository) {
    Default = repository;
}

(在我看来,在这种情况下将“集合”分开似乎更清楚,但你不必同意)

让呼叫者使用var product = YourFactory.Default.CreateProduct();

答案 5 :(得分:0)

@ThinkBeforeCoding - 在@ m4bwav的示例中,工厂从辅助方法获取有效ID,但它不是在任何地方的持久层中创建新记录。但是,如果我使用数据库自​​动生成的标识列作为我的身份,那么工厂似乎必须调用存储库来执行初始对象创建。你能否评论哪种方法“正确”?

答案 6 :(得分:0)

在构建器中,您可以拥有在entites上强制不变量所需的任何逻辑,使用Java作为开发语言的一个小例子......

我有一个用户实体,其中包含用户名,密码和电子邮件,所有属性都是必需的,所以我有:

public class User {

private String username;
private String password;
private String email:

/**
 * @throws IllegalArgumentException if the username is null, the password is null or the
 * email is null.
 */
public User(final String theUsername, final String thePassword, final String theEmail) {
Validate.notNull(theUsername);
Validate.notNull(thePassword);
Validate.notNull(theEmail);

this.username = theUsername;
this.password = thePassword;
this.email = theEmail;
}

// Getters / Setters / equal / hashCode / toString
}

然后我有UserBuilder:

public class UserBuilder {
private String username;
private String password;
private String email;

public UserBuilder withUsername(final String theUsername) {
Validate.notNull(theUsername);

this.username = theUsername;

return this;
}

public UserBuilder withPassword(final String thePassword) {
Validate.notNull(thePassword);

this.password = thePassword;

return this;
}

public UserBuilder withEmail(final String theEmail) {
Validate.notNull(theEmail);

this.email = theEmail;

return this;
}

public User build() {
User user = new User(this.username, this.password, this.email);

return user;
}
};

您可以像这样使用构建器:

UserBuilder builder = new UserBuilder();

try {
User user = builder.withUsername("pmviva").withPassword("My Nifty Password").withEmail("pmviva@somehost.com").build();
} catch (IllegalArgument exception) {
  // Tried to create the user with invalid arguments
}

工厂的唯一目的是创建有效的对象实例。为了不复制创建和水合代码,您可以让您的存储库从数据库中查询行集,并将对象的创建委托给传递行集数据的构建器。

希望这有帮助

由于 巴勃罗