1

I'd like to instantiate multiple (i.e. of the same type) different (i.e. differing combination of attributes) complex (i.e. many optional parameters) objects in my code.

I think that using a Builder as described by Joshua Bloch here and talked about over here is the best way to go.

A very basic implementation would look like this:

class ObjectBuilder implements ObjectBuilderInterface
{
 public function setAttributeA( $value ) : self
 {
  $this->attributeA = $value;
  return $this;
 }

 public function setAttributeB( $value ) : self
 {
  $this->attributeB = $value;
  return $this;
 }

.
.
.

 public function build() : Object
 {
  return new Object ($this->attributeA, $this->attributeB,...);
 }
}

BUT as far as I understand the inner workings of a builder, by using the setters on the builder object the builder itself has a state and couldn't be reused for another object without unsetting all attributes first.

A use case for example in a controller would look something like this:

public function FooController (ObjectBuilderInterface $builder, ...)
{
 $builder
  ->setAttributeA('A')
  ->setAttributeB('B');
 $instance1 = $builder->build();
 
 $builder
  ->setAttributeA('C')
  ->setAttributeB('D');
 $instance2 = $builder->build();
}

One could make an unset call at the end of build() but that feels somewhat wrong to me and in my above mentioned sources aswell as everywhere I looked for a real life implementation of such a builder (I live in Symfony-land and had a look into FormBuilder for example) was anything like an unset() used.

How is a Builder used to instantiate multiple different instances?

Eric
  • 11
  • 2
  • I'm not completely following your question - nothing in your definition here stops you from invoking `build` multiple times on your builder and producing multiple identically configured `Object` instances. If you're concerned that something might be modifying the state of the builder between those invocations because you need a new object incidental to an old object, you should probably be cloning the old object instance instead of reusing a separate creational pattern. – Preston Guillot Sep 21 '20 at 14:53
  • you are right, I did not clearly pointed out that I meant different instances of the same object type but with a differing combination of attributes. edited my question accordingly. – Eric Sep 21 '20 at 19:58

1 Answers1

0

I don't think there's a "right" answer here, but you have a few options.

  • Create a new builder for each object you intend to build e.g. from a factory.
  • Add the unset method you mention on the builder.
  • Reset the internal state of the builder each time you build.
  • Add a fluent startOver or newInstance member to your builder implementation, giving a clear way to indicate "this is a fresh start" at the call-site.
Preston Guillot
  • 6,493
  • 3
  • 30
  • 40