Builder Pattern

Use Case: Unit test object creation, any time object construction is complicated.

Definition

When piecewise object construction is complicated, provide and API for doing it in a brief and clearly expressed manner.

*A piecewise function is a function built from pieces of different functions over different intervals. *

Example FooBuilder

FooBuilder is used to construct the entity Foo, its state can be set if needs be with the methods WithId() and WithContactPerson(), this fluent API can be chained. Finally the Create() method returns an instance of Foo with the internal state set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace FooApp.Core.Builders
{
public class FooBuilder
{
private Guid _id;
private string _contactPerson;

public FooBuilder()
{
_id = Guid.NewGuid();
_contactPerson = "";
}

public FooBuilder WithId(Guid id)
{
_id = id;
return this;
}

public FooBuilder WithContactPerson(string contactPerson)
{
_contactPerson = contactPerson;
return this;
}

public Foo Create()
{
return new Foo()
{
Id = _id,
ContactPerson = _contactPerson
};
}
}
}

Example Use Case Of FooBuilder

In a test this could be used as follows with the assumption fooRepository -> SelectList returns a collection of type Foo.

1
2
3
4
5
6
7
var foo = new FooBuilder();

fooRepositoryMock.Setup(x => x.SelectList())
.Returns(new List<Foo>() {
foo.WithContactPerson("Bizz Bat").Create(),
foo.WithId("26ac6c17-0172-4d86-802c-d5b839f6215f").WithContactPerson("Hoe Bar").Create()
});

Example HTML Builder

Code example below from Dmitri Nesteruk

Life without Builder

Manually create some HTML, this will work but its not great.

1
2
3
4
5
6
7
8
9
10
var sb = new StringBuilder();
var words = new[] {"hello", "world"};

sb.Append("<ul>");
foreach (var word in words)
{
sb.AppendFormat("<li>{0}</li>", word);
}
sb.Append("</ul>");
WriteLine(sb);

Life With A Builder

Here the constructor for HtmlBuilder takes a rootName and the AddChild method takes childName and childText parameters. This is then encapsulating the creation and use of HtmlElement.

1
2
3
4
5
// ordinary non-fluent builder
var builder = new HtmlBuilder("ul");
builder.AddChild("li", "hello");
builder.AddChild("li", "world");
WriteLine(builder.ToString());

The method AddChildFluent returns a HtmlBuilder to allow you to chain methods together. This works by returning a reference to the original object. This is called a fluent interface.

1
2
3
4
5
var builder = new HtmlBuilder("ul");
builder
.AddChildFluent("li", "hello")
.AddChildFluent("li", "world");
WriteLine(builder);

References