我的 DDD 工厂类中应该包含哪些方法?

发布于 2024-07-14 10:44:31 字数 820 浏览 4 评论 0原文

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

请帮忙!

I am struggling to understand what my factory class should do in my DDD project. Yes a factory should be used for creating objects, but what exactly should it be doing. Consider the following Factory Class:

    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;
        }
    }

Should i be making a direct call to the repository from within the factory?

How should i manage object creation when retriving data from a database?

What do i need to make this class complete, what other methods should i have?

Should i be using this class to create the Product object from the domain and repository from right?

Please help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

风苍溪 2024-07-21 10:44:31

我应该直接打电话给
存储库中的
工厂?

不,在检索内容时不要使用工厂,仅在第一次创建工厂时才使用工厂。

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

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

我需要什么来上这门课
完成了,我还应该用什么方法
有吗?

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

我应该使用这个类来创建
来自域的 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();

Should i be making a direct call to
the repository from within the
factory?

No, don't use a factory when your retrieving stuff, use a factory only when you are creating it for the first time.

How should i manage object creation
when retriving data from a database?

Pass that data into the factory, if it is required for the object's initial creation.

What do i need to make this class
complete, what other methods should i
have?

Many factories are not even individual classes, they are just methods that provide object creation. You could fold the factory method into another class, if you felt like it was just going to call a parameterless constructor.

Should i be using this class to create
the Product object from the domain and
repository from right?

The repository is for getting (in a sense creating) existing objects, the factory is for the first time you create an object.

Initially many factories won't do much except call a constructor. But once you start refactoring and/or creating larger object hierarchies, factories become more relevant.

Explanation and Example:

For instance, in the project I'm working on I have an excel processor base class and many subclasses implementing that base class. I use the factory to get the proper one, and then call methods on it, ignorant of which subclass was returned.(Note: I changed some variable names and gutted/altered a lot of code)

Processor base class:

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

One of the Processor subclasses:

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

Factory:

 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...
      }
 }

Usage:

ExcelProcessor processor = CreateExcelProcessor(12, 34);
processor.Process();
紫南 2024-07-21 10:44:31

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

第一个案例是由工厂处理的。 您可以提供多种方法来在工厂上创建对象。
工厂方法应该返回有效的对象,因此您可以将参数传递给这些方法以提供所需的信息。

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

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

主要区别在于工厂将使用新标识实例化对象,而数据构建器将使用现有标识实例化对象。

Be carefull, there are two reasons to instantiate a new object : Creating it and rehydrating it from the database.

The first case is handled by the factory. You can provide several methods to create an object on the factory.
Factory methods should return valid objects, so you can pass parameters to these methods to provides required information.

The factory method can also chose the actual type to instantiate based on parameters.

You should not mix this with rehydrating from the database. This kind of instantiation should take values from the datarow and instantiate the object with it. I usualy call this a data builder instead of a factory.

The main difference is that the factory will instantiate an object with a new identity while the databuilder will instantiate an object with an already existing identity.

儭儭莪哋寶赑 2024-07-21 10:44:31

工厂的 Create 方法中应该包含将全新对象置于 VALID 状态所需的任何内容。

现在,对于某些对象,这意味着除此之外您不会执行任何操作:

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

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

这就是工厂好处的一部分。 现在,您只有一个驻留该特殊逻辑的位置,并且只有一个创建新对象的位置。

What should go in your factory's Create method is whatever is necessary to put a brand spanking new object into a VALID state.

Now, for some objects that means you won't do anything except this:

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

However, you may have business rules, default settings, or other requirements that you want to enforce when an object is created. In that case, you would put that logic in that method.

And that's part of the benefit of the Factory. You now have one and only one place where that special logic resides, and only one place where a new object gets created.

2024-07-21 10:44:31

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

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

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

希望这可以帮助。

I personally would use the factory in couple of circumstances:

1) Something elsewhere governs what type of objects this factory returns (ie. it can return objects depending on circumstances. For example return a stub object when I am testing, return an actual implementation when I am not (this is obviously more of Inversion of Control / Dependency Injection issue - but if you do not want to add containers to your project just yet)).

2) I have quite complex objects that have containers, dependencies, other relation etc. and they need to be built carefully to avoid creating null or meaningless references. For example if I have a Schedule object I may need some start, end date fields set - if the logic for retrieving, figuring out these date is complex enough I may not want the calling class to know about it and just call the default factory method that created the schedule object.

Hope this helps.

つ低調成傷 2024-07-21 10:44:31

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

或者如果您只是希望它充当全局注册的存储库,也许是这样的:(

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

在我看来,将“集" 在这种情况下,但您不必同意)

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

In the example given above, I'm a little unclear on the distinction between your factory and the repository. I wonder if you shouldn't simply add CreateProduct as a method to the repository, and using DI to push the repository into code that needs it? If the factory isn't doing anything, etc...

Or if you just want it to act as a globally registered repository, perhaps something like:

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

(in my mind it seems clearer to separate the "set" in this case, but you don't have to agree)

and have the callers use var product = YourFactory.Default.CreateProduct(); etc

苍风燃霜 2024-07-21 10:44:31

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

@ThinkBeforeCoding - in @m4bwav's example, the factory is getting a valid ID from a helper method, but it's not creating a new record in a persistence layer anywhere. If, however, I'm using a database auto-generated identity column as my identities, it seems like a factory would have to call into the repository to do the initial object creation. Can you comment on which method is "correct"?

怀中猫帐中妖 2024-07-21 10:44:31

在构建器中,您可以拥有在实体上强制执行不变量所需的任何逻辑,使用 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("[email protected]").build();
} catch (IllegalArgument exception) {
    // Tried to create the user with invalid arguments
}

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

希望这有帮助

谢谢
巴勃罗

In the builder you can have any logic you need to inforce the invariants on your entites, a little example using Java as development language...

I have a User entity that has a username, a password and an email, all attributes required so I have:

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
}

and then I have the 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;
    }
}

And you can use the builder like this:

UserBuilder builder = new UserBuilder();

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

The factory's solely purpose is th create valid instances of objects. In order not to duplicate creation and hydration code you can have your repositories to query a rowset from the database and delegate the creation of the object to a builder passing the rowset's data.

Hope this helps

Thanks
Pablo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文