【问题标题】:Factory Pattern where should this live in DDD?工厂模式在 DDD 中应该放在哪里?
【发布时间】:2012-11-28 02:11:49
【问题描述】:

我已经争论了一段时间,但仍然没有得出结论。 虽然我看到的大多数示例都有应用程序层中的工厂代码,但我倾向于认为它应该在域层中。 原因: 我有时会在我的工厂完成初始验证,我希望所有对象的创建都通过。 我希望此代码可用于我的对象的所有实例。 有时一个操作需要参数信息,传递给构造函数时感觉不自然。 还有一些不那么重要的原因。

是否有理由说明这是一种不好的做法? 这会破坏其他模式吗?

【问题讨论】:

    标签: c# design-patterns domain-driven-design architectural-patterns


    【解决方案1】:

    DDD 中的工厂只是factory pattern 的一个实例,因此应该在最有意义的地方使用它。另一个需要考虑的原则是information expert 模式,它本质上表明行为应该分配给最接近信息的类。因此,如果您想要强制执行某些特定于域的规则和逻辑,请将工厂放在域层中 - 毕竟,工厂创建域对象。但请注意,您可能在其他层中有其他类型的工厂。

    【讨论】:

      【解决方案2】:

      根据记忆,Eric Evans 的书中有一些示例,其中对象工厂在很大程度上是领域层的一部分。

      对我来说,在这里找到您的工厂是非常有意义的。

      【讨论】:

        【解决方案3】:

        +1 这样做。可访问性将是一个很好的理由,我会保持创建代码至少接近域模型层。否则,域模型的用户在查找受限访问构造函数时会很困惑如何专门实例化它。实际上,将其分开的一个合理理由是您有不同的有效方法来创建相同的东西,例如使用抽象工厂时通常是这种情况。

        如果我必须把它分开,我会把它放在例如一个包(在 Java 的情况下)至少与域模型相同级别,并始终与它一起发布,例如

        upper
          --> domain
          --> domain_factory
        

        【讨论】:

        • 看起来大多数人都同意它在域模型中。那么你推荐你的工厂存在于领域层的什么地方呢?单独的程序集、文件夹、命名空间?
        【解决方案4】:

        我更喜欢应用层中的工厂。

        如果您将工厂保留在域层中,当您需要复杂类型作为参数时(C# 代码示例),它们将无济于事:

        Application Layer:
        
        //this Factory resides in the Domain Layer and cannot reference anything else outside it
        Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(
                    string name, string code, string streetName,...
                    and lots of other parameters...);
        
        //these ones reside in Application Layer, thus can be much more simple and readable:
        Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(CreatePersonCommand);
        Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(PersonDTO);
        
        
        
        Domain Layer:
        
        public class Person : Entity<Person>
        {
            public Address Address {get;private set;}
            public Account Account {get;private set;}
            public Contact Contact {get;private set;}
            public string Name {get;private set;}
        
            public Person(string name, Address address,Account account, Contact contact)
            {
                //some validations & assigning values...
                this.Address = address;
                //and so on...
        
            }
        
        }
        
        public class Address:Entity<Address>{
            public string Code {get;private set;}
            public string StreetName {get;private set;}
            public int Number {get;private set;}
            public string Complement {get;private set;}
            public Address(string code, string streetName, int number, string complement?)
            {
                //some validations & assigning values...
                code = code;
            }
        
        }
        
        public class Account:Entity<Account>{
            public int Number {get;private set;}
        
            public Account(int number)
            {
                //some validations & assigning values...
                this.Number = number;
            }
        
        }
        
        //yout get the idea:
        //public class Contact...
        

        此外,没有义务将工厂保留在域层内(来自Domain Driven Design Quickly):

        因此,转移创建复杂实例的责任 对象和聚合到一个单独的对象,本身可能有 在领域模型中没有责任,但仍然是 域设计。提供一个封装所有复杂的接口 程序集,并且不需要客户端引用 被实例化的对象的具体类。创建整个 聚合为一个单元,强制执行它们的不变量。

        由于我不使用工厂将持久对象加载到内存中,因此不必从应用程序之外的其他层访问它们。原因如下(来自Domain Driven Design Quickly):

        另一个观察是工厂需要创建新对象 从头开始,或者他们需要重构对象 以前存在,但可能一直持续到 数据库。 将实体从静止状态带回记忆中 在数据库中的位置涉及完全不同的过程 创建一个新的。一个明显的区别是,新 对象不需要新的身份。该对象已经有一个。 违反不变量的处理方式不同。 当一个新的 对象是从头开始创建的,任何违反不变量的行为都会结束 在一个例外。我们不能用重新创建的对象来做到这一点 一个数据库。这些对象需要以某种方式修复,所以它们 可以正常工作,否则会丢失数据。

        【讨论】:

          【解决方案5】:

          如果建造者/工厂只依赖领域类和原语,则将它们放在领域层中,否则将它们放在领域层之外。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-02-20
            • 1970-01-01
            • 1970-01-01
            • 2010-10-11
            • 2012-02-17
            • 2018-11-20
            • 1970-01-01
            相关资源
            最近更新 更多