2010-01-28 56 views
6

我想知道在处理父子关系时,以下哪一项被认为是最佳实践?域驱动设计 - 父子关系模式 - 规范模式

1)下面的例子似乎是一种常见的做法,但是当创建一个孩子的实例时,只要它没有被添加到父代,它就会处于无效状态。不能这导致的问题就验证等

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public void AddChild(Child child) 
    { 
     child.Parent = this; 
     children.Add(child); 
    } 
} 


public class Child 
{ 
    internal Parent Parent 
    { 
     get; 
     set; 
    } 

    public Child() 
    { 
    } 
} 

2)下一个示例会照顾一个孩子必须始终与其父。

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public Child CreateChild() 
    { 
     var child = new Child(); 
     child.Parent = this; 
     children.Add(child); 
     return child; 
    } 
} 


public class Child 
{ 
    internal Parent Parent 
    { 
     get; 
     set; 
    } 

    internal Child() 
    { 
    } 
} 

3)在最后一个例子中,孩子负责与父母本身的关系。

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public void AddChild(Child child) 
    { 
     child.Parent = this; 
     children.Add(child); 
    } 
} 


public class Child 
{ 
    public Parent Parent 
    { 
     get; 
     set; 
    } 

    public Child(Parent parent) 
    { 
     this.Parent = parent; 
    } 
} 

哪种模式被认为是最好的?我相信模式2可能是最好的,因为如果没有与父母的关系,孩子永远不会存在。这会使得它更容易,例如实施可能会做这样的事情的规范模式时:

public class ChildSpecification 
{ 
    bool IsSatisfiedBy(Child child) 
    { 
     return child.Parent.Children.Where(someCondition).Count > 0; 
    } 
} 

如果一个孩子有一个父以上规格才能发挥作用。

您认为如何?你知道更好的方法吗?在此先感谢

回答

0

我倾向于使用选项(1) - 一直对我很好。重要的是不要将孩子们收集到外部世界 - 家长应该能够调解所有的访问。但是我很高兴在别处创建了一个孩子 - 我只在将它添加到父母时关心它,并且此时可以检查其是否有效等。

我不明白你的规范示例:如果父项的子项的任何的someCondition为true,则您的ChildSpecification将返回true。当然IsSatisfiedBy(儿童孩子)只应该返回true,如果特定的孩子作为参数传递满足条件。

+0

规范模式是关于我目前在我的一个项目中遇到的特殊情况。一个孩子有一个有效日期范围,它不应该与子集合中任何其他孩子的任何其他有效日期范围相交。你会认为这是父母的规范吗? – Chris 2010-01-28 16:25:09

+0

我可能会在Parent的addChild()方法中实现这个作为警戒条件。家长然后不允许添加例如抛出异常。在这种情况下,我可能不会使用规范。 – alasdairg 2010-01-28 17:07:02

+0

但我需要在UI上检查。所以当抛出异常时,我不得不接受这一点。这也不是很优雅。而afaik关于规范的好处是我可以在很多不同的场景中使用它,例如1.)在我的域oe中2.)在客户端应用程序中预先验证业务逻辑。或者我错了? – Chris 2010-01-28 17:20:10

5

我绝对喜欢建议2号,但我认为它忽略了在3发现,即如果没有Parent不能存在Child对象应采取在其构造Parent对象重要的东西。此外,属性Child类应该只读。 所以,你最终会得到这样的:

public class Parent 
{ 
    private ICollection<Child> children; 

    public ReadOnlyCollection Children { get; } 

    public Child CreateChild() 
    { 
     var child = new Child(this); 
     children.Add(child); 
     return child; 
    } 
} 


public class Child 
{ 
    internal Parent Parent 
    { 
     get; 
     private set; 
    } 

    internal Child(Parent parent) 
    { 
     this.Parent = parent; 
    } 
} 
+0

我会这样做,如果规范是一个孩子应该总是有一个父,并且不知道它的父母是不能创建的。 所以,只是2和3的组合。 +1 – 2010-01-28 17:05:28

1

因为我刚刚遇到了同样的设计desissions和问题,为回答我会后对这个问题的解决方案我的视力仍然没有标明 - 也许它会帮助任何人。这个解决方案实际上非常适合NHibernate使用。

public class Parent 
{ 
    private readonly ISet<Child> _children = new HashedSet<Child>(); 
    public virtual IEnumerable<Child> Children { get { return new ImmutableSet<Child> (this._children); } } 


    protected internal virtual void AddChild (Child child) 
    { 
     this._children.Add(child); 
    } 
} 


public class Child 
{ 
    public virtual Parent Parent { get; protected set; } 


    protected Child() 
    { 
    } 


    public static Create (Parent parent) 
    { 
     if (parent == null) 
      throw new ArgumentNullException ("parent"); 

     var child = new Child 
     { 
      Parent = parent 
     }; 

     child.Parent.AddChild (child); 

     return child; 
    } 
} 

这是从你的#2选项不同的方式,子对象(和无效它的初始值)的创建聚集withing子对象本身,而不是在父对象,你在#2建议。

如果我们用个人工厂方法创建子对象(Child.Create),我不确定它是否被认为是不好的设计。

我希望有更多使用DDD经验的人可以对此发表评论。