Below is the code I have tried, is there a better way to do this?
Edit: I used this again and simplified it to remove the redundant value-checking in setters.
I recently implemented a version that is working out nicely.
Builders are factories which cache the most recent instance. Derived builders create instances and clear the cache when anything changes.
The base class is straightforward:
public abstract class Builder<T> : IBuilder<T>
{
public static implicit operator T(Builder<T> builder)
{
return builder.Instance;
}
private T _instance;
public bool HasInstance { get; private set; }
public T Instance
{
get
{
if(!HasInstance)
{
_instance = CreateInstance();
HasInstance = true;
}
return _instance;
}
}
protected abstract T CreateInstance();
public void ClearInstance()
{
_instance = default(T);
HasInstance = false;
}
}
The problem we are solving is more subtle. Let's say we have the concept of an Order
:
public class Order
{
public string ReferenceNumber { get; private set; }
public DateTime? ApprovedDateTime { get; private set; }
public void Approve()
{
ApprovedDateTime = DateTime.Now;
}
}
ReferenceNumber
does not change after creation, so we model it read-only via the constructor:
public Order(string referenceNumber)
{
// ... validate ...
ReferenceNumber = referenceNumber;
}
How do we reconstitute an existing conceptual Order
from, say, database data?
This is the root of the ORM disconnect: it tends to force public setters on ReferenceNumber
and ApprovedDateTime
for technical convenience. What was a clear truth is hidden to future readers; we could even say it is an incorrect model. (The same is true for extension points: forcing virtual
removes the ability for base classes to communicate their intent.)
A Builder
with special knowledge is a useful pattern. An alternative to nested types would be internal
access. It enables mutability, domain behavior (POCO), and, as a bonus, the "prototype" pattern mentioned by Jon Skeet.
First, add an internal
constructor to Order
:
internal Order(string referenceNumber, DateTime? approvedDateTime)
{
ReferenceNumber = referenceNumber;
ApprovedDateTime = approvedDateTime;
}
Then, add a Builder
with mutable properties:
public class OrderBuilder : Builder<Order>
{
private string _referenceNumber;
private DateTime? _approvedDateTime;
public override Order Create()
{
return new Order(_referenceNumber, _approvedDateTime);
}
public string ReferenceNumber
{
get { return _referenceNumber; }
set { SetField(ref _referenceNumber, value); }
}
public DateTime? ApprovedDateTime
{
get { return _approvedDateTime; }
set { SetField(ref _approvedDateTime, value); }
}
}
The interesting bit is the SetField
calls. Defined by Builder
, it encapsulates the pattern of "set the backing field if different, then clear the instance" that would otherwise be in the property setters:
protected bool SetField<TField>(
ref TField field,
TField newValue,
IEqualityComparer<T> equalityComparer = null)
{
equalityComparer = equalityComparer ?? EqualityComparer<TField>.Default;
var different = !equalityComparer.Equals(field, newValue);
if(different)
{
field = newValue;
ClearInstance();
}
return different;
}
We use ref to allow us to modify the backing field. We also use the default equality comparer but allow callers to override it.
Finally, when we need to reconstitute an Order
, we use OrderBuilder
with the implicit cast:
Order order = new OrderBuilder
{
ReferenceNumber = "ABC123",
ApprovedDateTime = new DateTime(2008, 11, 25)
};
This got really long. Hope it helps!
The reason to use Joshua Bloch's builder pattern was to create a complex object out of parts, and also to make it immutable.
In this particular case, using optional, named parameters in C# 4.0 is cleaner. You give up some flexibility in design (don't rename the parameters), but you get better maintainable code, easier.
If the NutritionFacts code is:
public class NutritionFacts
{
public int servingSize { get; private set; }
public int servings { get; private set; }
public int calories { get; private set; }
public int fat { get; private set; }
public int carbohydrate { get; private set; }
public int sodium { get; private set; }
public NutritionFacts(int servingSize, int servings, int calories = 0, int fat = 0, int carbohydrate = 0, int sodium = 0)
{
this.servingSize = servingSize;
this.servings = servings;
this.calories = calories;
this.fat = fat;
this.carbohydrate = carbohydrate;
this.sodium = sodium;
}
}
Then a client would use it as
NutritionFacts nf2 = new NutritionFacts(240, 2, calories: 100, fat: 40);
If the construction is more complex this would need to be tweaked; if the "building" of calories is more than putting in an integer, it's conceivable that other helper objects would be needed.
In Protocol Buffers, we implement the builder pattern like this (vastly simplified):
public sealed class SomeMessage
{
public string Name { get; private set; }
public int Age { get; private set; }
// Can only be called in this class and nested types
private SomeMessage() {}
public sealed class Builder
{
private SomeMessage message = new SomeMessage();
public string Name
{
get { return message.Name; }
set { message.Name = value; }
}
public int Age
{
get { return message.Age; }
set { message.Age = value; }
}
public SomeMessage Build()
{
// Check for optional fields etc here
SomeMessage ret = message;
message = null; // Builder is invalid after this
return ret;
}
}
}
This isn't quite the same as the pattern in EJ2, but:
StringBuilder
does.Build()
to guarantee immutability. This unfortunately means it can't be used as a sort of "prototype" in the way that the EJ2 version can.this
for the sake of pre-C#3 users.I haven't really looked into inheritance with the builder pattern - it's not supported in Protocol Buffers anyway. I suspect it's quite tricky.
This blog entry might be of interest
A neat variation on the pattern in C# is the use of an implicit cast operator to make the final call to Build() unnecessary:
public class CustomerBuilder
{
......
public static implicit operator Customer( CustomerBuilder builder )
{
return builder.Build();
}
}