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

我正在努力了解我的工厂类应该在我的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对象?

请帮忙!

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

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

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

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

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

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

我是否应该使用此类从域和存储库创建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(); 

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

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

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

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

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

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

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

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

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

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

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

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

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

希望这可以帮助。

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

或者,如果您只是希望它充当全球注册的存储库,可能类似于:

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

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

并让调用者使用var product = YourFactory.Default.CreateProduct(); 等等

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

在构建器中,您可以拥有在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 } 

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

希望这可以帮助

谢谢巴勃罗