7

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.

asked Feb 8, 2016 at 16:50
6
  • 2
    I guess design patterns are ontopic here, but huge chunks of source code are definitely now. Please use a small example (in pseudo code) to make your point. Also, make sure that your are not asking a code review question; for this site, you'd have to ask about a concept or for a reference. Commented Feb 8, 2016 at 21:19
  • 1
    @Raphael - Apologies. I'm not looking for a code review. I figured that actual code might make the question clearer. Thanks for your comment. I'm really looking for a pattern recommendation here. I can come up with several solutions, but one of the benefits of patterns is that they facilitate communication and understanding. With the solution I have come up with, it's difficult to clearly and concisely explain what I did and why. If I use a documented pattern, then the what and why already exist, and I just need to reference them. I haven't found a pattern that fits my requirements, though. Commented Feb 9, 2016 at 15:34
  • @D.W. - I have added a section to address your question. Hopefully this makes what I'm looking for a bit clearer. Thanks for your comment. Commented Feb 9, 2016 at 15:35
  • The answer here most likely depends a lot on how you are deciding what As and Bs to create. If you could give more context around what data and/or events lead to the creation of these object, it would help. Commented Sep 8, 2016 at 18:17
  • Also, are these immutable objects or is there simply a minimum of 2 Bs and more can be added to A later? Commented Sep 8, 2016 at 18:18

1 Answer 1

1

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

answered Feb 11, 2016 at 10:50

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.