Specification pattern implementation help

.net, c#, domain-driven-design, java, oop

Solution

public class Parent {
  private List<Child> children;

  public ICollection<Child> Children { 
    get { return children.AsReadOnly(); } 
  }

  public void AddChild(Child child) {
    if (!child.IsSatisfiedBy(this)) throw new Exception();
    child.Parent = this;
    children.Add(child);
  }
}

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

  public DateTime ValidFrom;
  public DateTime ValidTo;

  public bool IsSatisfiedBy(Parent parent) { // can also be used before calling parent.AddChild
    return parent.Children.All(c => !Overlaps(c));
  }

  bool Overlaps(Child c) { 
    return ValidFrom <= c.ValidTo && c.ValidFrom <= ValidTo;
  }
}

UPDATE:

But of course, the real power of the specification pattern is when you can plug in and combine different rules. You can have an interface like this (possibly with a better name):

public interface ISpecification {
  bool IsSatisfiedBy(Parent parent, Child candidate);
}

And then use it like this on `Parent`:

public class Parent {
  List<Child> children = new List<Child>();
  ISpecification childValiditySpec;
  public Parent(ISpecification childValiditySpec) {
    this.childValiditySpec = childValiditySpec;
  }
  public ICollection<Child> Children {
    get { return children.AsReadOnly(); }
  }
  public bool IsSatisfiedBy(Child child) {
    return childValiditySpec.IsSatisfiedBy(this, child);
  }
  public void AddChild(Child child) {
    if (!IsSatisfiedBy(child)) throw new Exception();
    child.Parent = this;
    children.Add(child);
  }
}

`Child` would be simple:

public class Child {
  internal Parent Parent { get; set; }
  public DateTime ValidFrom;
  public DateTime ValidTo;
}

And you could implement multiple specifications, or composite specifications. This is the one from your example:

public class NonOverlappingChildSpec : ISpecification {
  public bool IsSatisfiedBy(Parent parent, Child candidate) {
    return parent.Children.All(child => !Overlaps(child, candidate));
  }
  bool Overlaps(Child c1, Child c2) {
    return c1.ValidFrom <= c2.ValidTo && c2.ValidFrom <= c1.ValidTo;
  }
}

Note that it makes more sense to make `Child`'s public data immutable (only set through the constructor) so that no instance can have its data changed in a way that would invalidate a `Parent`.

Also, consider encapsulating the date range in a specialized abstraction.

Problem

I've a question regarding enforcing a business rule via a specification pattern. Consider the following example: ``` 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 DateTime ValidFrom; public DateTime ValidTo; public Child() { } } ``` The business rule should enforce that there cannot be a child in the collection which validity period intersects with another. For that I would like to implement a specification that is then be used to throw an exception if an invalid child is added AND as well can be used to check whether the rule will be violated BEFORE adding the child. Like: ``` public class ChildValiditySpecification { bool IsSatisfiedBy(Child child) { return child.Parent.Children.Where(<validityIntersectsCondition here>).Count > 0; } } ``` But in this example the child accesses the parent. And to me that doesnt seem that correct. That parent might not exist when the child has not been added to the parent yet. How would you implement it?

Original source