Design pattern to handle construction of complex objects with a [1 → 1..*] multiplicity relationship

api-designdesign-patterns

I have two classes (A and B) that are both complex to construct, with multiple properties that must be validated at construction time. I want to use the Builder pattern to construct these objects, but among the constraints on construction of these objects are:

  • An instance of A must contain multiple instances of B
  • Each instance of B has a child relationship to a single instance of A

In addition, I need to be able to add new instances of B to A after A has been constructed.

It seems like this must be a pretty common scenario. Is there some pattern other than Builder or to augment Builder that handles this situation?

Option 1 – With a "placeholder" class

The best solution that I have come up with so far uses an impotent version of the Builder class, with the Build() method removed (I call it a Placeholder) to specify the parameters for the child class.

class ClassA {
    get propertyC
    ...
    get list<A> children

    restricted constructor() {}

    BBuilder AddChild() {}
}

class ClassB {
    get propertyD
    ...
    get ClassA parent

    restricted constructor(ClassA parent)
}

class ABuilder {
    get / set propertyC
    ...
    BPlaceholder AddChild() {}

    ClassA Build() {
        VALIDATE properties
        BUILD ClassA
        foreach child { BUILD child }
    }
}

class BPlaceholder {
    get / set propertyD
    ...

    restricted constructor(ABuilder parent) {}
}

class BBuilder : BPlaceholder {
    restricted constructor(ClassA parent) {}

    ClassB Build() {
        VALIDATE properties
        BUILD child
    }
}

Notice that, of the 5 classes in this example, the only one that can be simply constructed is ABuilder. The other classes are all instantiated, either directly or indirectly, through this class.

Option 2 – Similar to Abstract Factory

Another possibility I have considered is to remove the Build() method from both Builder classes (in which case they are no longer Builders) and pass both classes to a third Factory class to perform the construction, similar to Abstract Factory. This doesn't seem as nice to me for two reasons, though:

  • The interface doesn't intuitively guide you to the proper use
  • Construction of B after A has already been instantiated is substantially different from construction of B before A has been instantiated

Rationale for avoidance of simple construction

One possibility is to just use simple construction, something like this:

objA = new ClassA()
objA.Add(new ClassB(objA))

This is obviously a possibility, but it is missing a key element found in the Builder pattern. Builder allows you to ensure that there is no way to construct an "incomplete" instance of a class. My constraints state that a valid instance of ClassA must have at least one child of type ClassB. In the example above, objA exists (for a short time) without any children, and is hence invalid.

Best Answer

I would do something along the lines of...

public class A
{
    public List<B> childern {get;private set;}
    public A(DataReader dataForA, DataReader dataForBs)
    {
        //validate and set A properties from first datareader,
        ///validate we have at least one B
        while(dataForBs.Read())
        {
            var parent = this;
            var b = new B(dataForBs, parent) //validate b data in constructor
            this.childern.Add(b);
        }
    }
}

Using datareaders here for simplicity, but obviously you could have any 'raw' data construct or just a list of parameters.

Since all the validation, child construction and linking is done in the constructor for A or B it should be impossible to have an instance of either A with no children or B with no parent.

You will need to create your own version of List which you cant remove everything from but I guess this is outside the scope of your problem

Related Topic