Reputation: 7919
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
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
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
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
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
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