简体   繁体   English

DDD工厂实体值对象

[英]DDD Factory Entity Value Object

I have been increasingly adopting DDD / Onion Architecture in my current project. 在我目前的项目中,我越来越多地采用DDD /洋葱架构。 One of the many things I am still unclear about is how much encapsulation should there be. 我仍然不清楚的许多事情之一是应该有多少封装。 Easier explained with a concrete example. 用一个具体的例子更容易解释。

Example

namespace MyProject.Model
{
    public class ComplexEntity
    {
        private int _id;
        public int Id { get {return _id;} }
        public ValueObjectA ValueA {get; set;}
        public bool IsBool {get; set;}
        public ComplexEntity(ValueObjectA a, bool isBool)
        {
            // Do some validation first
            ValueA = a;
            ValueB = b;
            IsBool = isBool;
        }
    }

    public class ValueObjectA
    {
        public bool IsBoolA {get; private set;}
        public bool IsBoolB {get; private set;}
        public ValueObjectA(bool a, bool b)
        {
            IsBoolA = a;
            IsBoolB = b;
        }
    }

    public Interface IComplextEntityFactory
    {
        // Option 1
        ComplexEntity Create(
            ValueObjectA a,
            bool IsBool);

        // Option 2
        ComplexEntity Create(
            bool valueABool a,
            bool valueBBool b,
            bool isBool);
    }
}

Question

For the factory of an entity, do you, 对于一个实体的工厂,你呢,

  1. Expect the caller to construct the value objects for you and use it to initialize the ComplexEntity? 期望调用者为您构造值对象并使用它来初始化ComplexEntity?
  2. Have essentially CLR basic types being passed to the factory and you construct every ValueObject that makes up the Entity? 基本上将CLR基本类型传递给工厂并构造构成实体的每个ValueObject吗?

I am leaning towards option 2 but I can't seem to find supporting literature for it. 我倾向于选择2,但我似乎无法找到它的支持文献。

Edit 1 编辑1

To be honest I am still no clearer. 说实话,我仍然不清楚。 What about aggregate roots? 聚集根源怎么样?

When my entity refers to other entities, eg below. 当我的实体引用其他实体时,例如下面。

  1. Should I have an IComplexEntityFactory , ILessComplexEntityFactory ? 我应该有一个IComplexEntityFactoryILessComplexEntityFactory吗? Or just an IComplexEntityAggregateFactory that creates the LessComplexEntity and instantiates ComplexEntity ? 或者只是一个IComplexEntityAggregateFactory创建LessComplexEntity并实例化ComplexEntity?
  2. In the case of the AggregateFactory solution, what do I do if the LessComplexEntity attribtues that have been passed to the factory correspond to an existing LessComplexEntity? 对于AggregateFactory解决方案,如果已传递给工厂的LessComplexEntity属性对应于现有的LessComplexEntity,我该怎么办? Do I retrieve and reuse it from a Repository? 我是否从存储库中检索并重用它? Or do I return an error to the caller? 或者我是否向调用者返回错误?
  3. What would the method signature be for the AggregateFactory? 方法签名对于AggregateFactory会是什么? Would it be (ValueObject a, ValueObject b) , or (ValueObject value, LessCompelxEntity entity) 它是(ValueObject a, ValueObject b)还是(ValueObject value, LessCompelxEntity entity)

    public class ComplexEntity { private readonly int _id; public class ComplexEntity {private readonly int _id; public int Id { get { return _id;} } public int Id {get {return _id;}}

     public ValueObject Value {get; set;} public LessComplexEntity Entity {get; set;} public ComplexEntity(int id, ValueObject value, LessComplexEntity entity) { } 

    } }

    public class LessComplexEntity { private readonly int _id; public class LessComplexEntity {private readonly int _id; public int Id { get {return _id;} } public ValueObject Value {get; public int Id {get {return _id;}} public ValueObject Value {get; set;} public LessComplexEntity(int id, ValuObject value) { } } set;} public LessComplexEntity(int id,ValuObject value){}}

I'd choose option 1. 我会选择选项1。

  • Makes explicit to everyone that you need a ValueObjectA to build a ComplexEntity. 向每个人明确表示您需要使用ValueObjectA来构建ComplexEntity。 More readable, less head scratching when you see the method used somewhere. 当您看到某处使用的方法时,更易读,更少抓头。

  • If ValueObjectA changes, you'll have to modify the code in only one place (the factory's caller) as opposed to changing the signature of Create() + adjusting the value object creation inside the factory. 如果ValueObjectA发生更改,则必须仅在一个位置(工厂的调用者)修改代码,而不是更改Create()的签名+调整工厂内的值对象创建。

  • Less parameters to the factory's Create() method is less verbose and more readable. 工厂的Create()方法的参数较少,更简洁,更易读。

  • In unit tests, it gives you a lot more options to be able to inject the ValueObjectA you want. 在单元测试中,它为您提供了更多选项,以便能够注入您想要的ValueObjectA。 There's not a lot you can do in terms of testing if you keep ValueObjectA's creation hidden inside the factory entirely. 如果你将ValueObjectA的创建完全隐藏在工厂中,那么在测试方面你就无法做很多事情。

[Edit] [编辑]

It's not clear what your real problem is with Aggregate Roots and Factories, but you shouldn't mix up the responsibility to retrieve/rehydrate an existing object with the responsibility to create an object. 目前尚不清楚你的实际问题是什么与聚合根和工厂有关,但你不应该把检索/补充现有对象的责任与创建对象的责任混为一谈。

I'd take as a general rule that a Factory's job is to assemble a new object from smaller parts (whether they be primitive types, value objects, entities...) 作为一般规则,工厂的工作是从较小的部分组装新对象(无论它们是原始类型,值对象,实体......)

The Factory should be provided with all these parts, it is not its duty to retrieve or rehydrate them from somewhere. 工厂应该提供所有这些部件,从一些地方检索或补充它们不是它的责任。 You can leave that to the Factory's caller. 您可以将其留给工厂的来电者。 It will make the Factory more cohesive and coupled to less classes (Repositories, etc.) 它将使工厂更具凝聚力,并与更少的类(存储库等)耦合

I prefer Option #1 as it would reduce the number of parameters required on the factory method. 我更喜欢选项#1,因为它会减少工厂方法所需的参数数量。 But my advice would be to only use a factory when the aggregate in question requires a creation strategy. 但我的建议是,当有问题的聚合需要创建策略时,才使用工厂。

In one of your comments you say: 在你的一条评论中,你说:

"..but then I don't understand the benefit of the factory. All it would be doing then is just calling the constructor of the ComplexEntity rather than creating all the subcomponents that make it up." “但是我不明白工厂的好处。那么它所做的只是调用ComplexEntity的构造函数而不是创建构成它的所有子组件。”

The factory's job is to make decisions on how to instantiate the aggregate by looking at the data passed to it. 工厂的工作是通过查看传递给它的数据来决定如何实例化聚合。 In my experience a common scenario where this is required is where inheritance/polymorphism has been used. 根据我的经验,需要这种情况的常见情况是使用了继承/多态。 For example, imagine you have an abstract Account class, with two sub classes: SavingsAccount & CurrentAccount. 例如,假设您有一个抽象的Account类,它有两个子类:SavingsAccount和CurrentAccount。 The factory's job is to decide on which one to instantiate, given some data. 工厂的工作是根据一些数据决定实例化哪一个。

Another potential benefit of a factory is how expressive you can be. 工厂的另一个潜在好处是你的表现力如何。 If an aggregate can be instantiated in more than one way (ie different arguments) then this can be expressed better with a method name on a factory than an overloaded constructor. 如果聚合可以以多种方式实例化(即不同的参数),那么可以使用工厂上的方法名称而不是重载的构造函数来更好地表达聚合。

As I say, my advice is to not create a factory for every aggregate unless for one of the above reasons. 正如我所说,除非出于上述原因之一,我的建议是不为每个集合创建工厂。 Otherwise, as you have pointed out, it will just be one line calling the constructor with the same arguments passed to it. 否则,正如您所指出的那样,它只是一行调用构造函数,并传递相同的参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM