DDD工厂实体值对象

时间:2012-07-09 12:29:53

标签: c# domain-driven-design factory onion-architecture

我在我当前的项目中越来越多地采用DDD /洋葱架构。 我仍然不清楚的许多事情之一是应该有多少封装。 用一个具体的例子更容易解释。

示例

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

问题

对于实体的工厂,你呢,

  1. 期望调用者为您构造值对象并使用它来初始化ComplexEntity?
  2. 基本上将CLR基本类型传递给工厂并构建构成实体的每个ValueObject吗?
  3. 我倾向于选择2,但我似乎无法找到支持文献。

    修改1

    说实话,我仍然不清楚。集合根源怎么样?

    当我的实体引用其他实体时,例如下方。

    1. 我应该IComplexEntityFactoryILessComplexEntityFactory吗?或者只是创建LessComplexEntity的IComplexEntityAggregateFactory并实例化ComplexEntity?
    2. 对于AggregateFactory解决方案,如果已传递给工厂的LessComplexEntity属性对应于现有的LessComplexEntity,我该怎么办?我是否从存储库中检索并重用它?或者我是否向调用者返回错误?
    3. AggregateFactory的方法签名是什么?会是(ValueObject a, ValueObject b)还是(ValueObject value, LessCompelxEntity entity)

      公共类ComplexEntity {     private readonly int _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)
      {
      }
      

      }

      公共类LessComplexEntity {     private readonly int _id;     public int Id {get {return _id;}}     public ValueObject Value {get;组;}     public LessComplexEntity(int id,ValuObject value)     {     } }

2 个答案:

答案 0 :(得分:3)

我会选择选项1。

  • 向每个人明确表示您需要使用ValueObjectA来构建ComplexEntity。当你看到某处使用的方法时,更易读,更少抓头。

  • 如果ValueObjectA发生更改,则必须仅在一个位置(工厂的调用者)修改代码,而不是更改Create()的签名+调整工厂内的值对象创建。

  • 工厂的Create()方法的参数较少,冗长,可读性更强。

  • 在单元测试中,它为您提供了更多选项,以便能够注入您想要的ValueObjectA。如果将ValueObjectA的创建完全隐藏在工厂内,那么在测试方面你可以做的很多。

<强> [编辑]

目前尚不清楚您的聚集根和工厂的真正问题是什么,但您不应该将检索/补充现有对象的责任与创建对象的责任混为一谈。

作为一般规则,工厂的工作是从较小的部分组装一个新对象(无论它们是原始类型,值对象,实体......)

工厂应该提供所有这些部件,检索或从某个地方补充水分不是它的责任。您可以将其留给工厂的来电者。它将使工厂更cohesive并与更少的类(存储库等)相结合

答案 1 :(得分:1)

我更喜欢选项#1,因为它会减少工厂方法所需的参数数量。但我的建议是,当有问题的聚合需要创建策略时,才使用工厂。

在你的一条评论中,你说:

  

“..然后我不明白工厂的好处。那么它所做的只是调用ComplexEntity的构造函数而不是创建构成它的所有子组件。”

工厂的工作是通过查看传递给它的数据来决定如何实例化聚合。根据我的经验,需要这种情况的常见情况是使用了继承/多态。例如,假设您有一个抽象的Account类,有两个子类:SavingsAccount&amp; CurrentAccount。工厂的工作是根据一些数据决定实例化哪一个。

工厂的另一个潜在好处是你的表现力如何。如果聚合可以以多种方式实例化(即不同的参数),那么这可以用工厂上的方法名称比重载的构造函数更好地表达。

正如我所说,除非出于上述原因之一,我的建议是不为每个集合创建工厂。否则,正如您所指出的那样,它只是一行调用构造函数,并传递相同的参数。