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
Domain-Driven Design(DDD) is a collection of principles and patterns that help developers craft elegant object systems. Properly applied it can lead to software abstractions called domain models. These models encapsulate complex business logic, closing the gap between business reality and code.
An aggregate is a domain-driven design pattern. It's a cluster of domain objects (e.g. entity, value object), treated as one single unit. A car is a good example. It consists of wheels, lights and an engine.
Tactical DDD is when you define your domain models with more precision. The tactical patterns are applied within a single bounded context. In a microservices architecture, we are particularly interested in the entity and aggregate patterns.
Domain-driven design (DDD) is a software development philosophy centered around the domain, or sphere of knowledge, of those that use it. The approach enables the development of software that is focused on the complex requirements of those that need it and doesn't waste effort on anything unneeded.
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With