Alex
Alex

Reputation: 7919

Should a Builder be created by a Factory?

Complex objects are often created by the Builder pattern, where a Builder is an object dedicated to the creation of a single object through multiple methods. E.G. (pseudocode):

class PersonBuilder
    PersonBuilder Named(string name)
        this.name = name
        return this

    PersonBuilder Aged(int age)
        this.age = age
        return this

    Person GetPerson()
        return new Person(this.name, this.age)

This stateful structure with a fluent interface is common in the builder pattern:

myPerson = builder.Named("John").Aged(20).GetPerson();

Therefore, is it wise to create a PersonBuilderFactory from which you can create the builder? Or should you just take a dependency on a PersonBuilder and assume that your class will be injected with a new object? The latter approach means that when you have created your Person you should probably reset the builder. What is best practice here, and why?

Upvotes: 1

Views: 159

Answers (5)

Alex
Alex

Reputation: 7919

(As the commentor to my question has not opted to respond with an answer I will provide one that I think is acceptable)

Making your Builder immutable is answer to this problem. You can take advantage of the fact that an instance will have access to the private members of another instance. The original example thus becomes:

class PersonBuilder
    PersonBuilder(PersonBuilder copy) // copy constructor
        this.name = copy.name
        this.age = copy.age

    PersonBuilder Named(string name)
        newBuilder = new PersonBuilder(this)
        newBuilder.name = name
        return newBuilder

    PersonBuilder Aged(int age)
        newBuilder = new PersonBuilder(this)
        newBuilder.age = age
        return newBuilder

    Person GetPerson()
        return new Person(this.name, this.age)

This way, it is still possible to use the builder like so:

myPerson = builder.Named("John").Aged(20).GetPerson();

However, the original builder object will remain unchanged, and can be used repeatedly.

Thanks to Ben James for the suggestion.

Upvotes: 0

FireAlkazar
FireAlkazar

Reputation: 1882

In original Builder pattern there is a Director.
As I understand, the director incapsulates the work with builder. If you need to reset the builder somehow(for example, call dispose for TcpClient inside builder), do that in director.

How and where to instantiate a concrete builder?
If, for example, you have 3 document formats(TXT, PDF, Excel) and user can select among of them, you will need factory in this case

class BuilderFactory
{
  public IBuilder Create(DocumentType type)
  {
    if(type == DocumentType.TXT)
      return new TxtBuilder();

    if(type == DocumentType.Pdf)
      return new PdfBuilder();

    //...
  }
}

If during application execution time builder is the same, you can put the concrete builder in config(espesially if you use DI).
If you know the concrete builder at design time you can just use new operator.

Upvotes: 1

ManMohan Vyas
ManMohan Vyas

Reputation: 4062

Generally builder should be immutable there should be no concept of reset in it.but still that depends on your need on what u need to achieve ....

Upvotes: -1

rascio
rascio

Reputation: 9279

It depends a lot on your builder class...I prefer create a XXXBuilderFactory when I have to apply some logic in the Builder creation, otherwise, I think, just the builder is enough in this way the code remains simpler.

Upvotes: 0

Roger Lipscombe
Roger Lipscombe

Reputation: 91825

In C#, I like the following pattern (which requires lambda functions):

var person = PersonBuilder.Create(p => p.Named("John").Aged(20));

Where it's implemented something like this:

class PersonBuilder
{
    private PersonBuilder() { /* ... */ }

    public static Person Create(Action<PersonBuilder> configure)
    {
        var builder = new PersonBuilder();
        configure(builder);
        return builder.Build();
    }

    // ...
}

Upvotes: 1

Related Questions