views:

244

answers:

2

Hi all,

I was wondering which of the following is considered to be a best practice when dealing with parent child relationships.

1) The following example seems to be a common practice, but when creating an instance of a child, it will be in an invalid state as long as it is not added to the parent. Couldn't this lead to problems regarding validation etc.

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) The next sample would take care that a child must always be related to its parent.

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) In the last example that child takes care of the relation to its parent itself.

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

Which pattern is considered the best? I believe that pattern 2 might be the best since then a child can never exist without a relation to its parent. This would make it easier e.g. when implementing a specification pattern that might do things like:

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

The above specification can only work if a child has a parent.

What do you think? Do you know better ways? Thanks in advance

A: 

I tend to use option (1) - has always worked well for me. The important thing is not to expose the children collection itself to the outside world - the Parent should be able to mediate all the access. But I'm perfectly happy for a Child to be created elsewhere - I only care about it when it gets added to the Parent, and at this point it can be checked for validity etc. etc.

I don't understand your specification example: it seems like your ChildSpecification would return true if any of the parent's children has someCondition as true. Surely IsSatisfiedBy(Child child) should only return true if the specific child passed as a parameter satisfied the condition.

alasdairg
The specification pattern is about a special case I'm currently having in one of my projects. A child has a validity date range, which should'nt intersect with any other validity date ranges of any other child within the child collection. Would you consider this a specification for the parent?
Chris
I would probably implement this as a guard condition in the addChild() method of the Parent. The Parent would then disallow the add e.g. by throwing an exception. I probably wouldn't use a specification in this case.
alasdairg
But I need to check that on the UI as well. So when in exception is thrown, I would have to catch that. This isn't very elegant either. And afaik the good thing about specifications is that I could use it in lots of different scenarios like 1.) within my domain oe 2.) within a client application to pre-validate business logic. Or am I wrong?
Chris
+2  A: 

I definitely like suggestion number 2, but I think that it misses something important that is found in 3, namely that if a Child object cannot exist without a Parent it should take a Parent object in its constructor. Furthermore the Parent property on the Child class should be read only. So you would end up with something like:

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;
    } 
} 
klausbyskov
Frederik Gheysels