Last active
August 27, 2015 08:32
-
-
Save jhgbrt/74e67c4781b935aa311b to your computer and use it in GitHub Desktop.
Basic Functional Fluent Builder
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
// Factory methods provided in non-generic abstract base class | |
public abstract class Builder | |
{ | |
public static Builder<T> For<T>() where T : new() | |
{ | |
return new Builder<T>(() => new T()); | |
} | |
public static Builder<T> For<T>(Func<T> ctor) | |
{ | |
return new Builder<T>(ctor); | |
} | |
} | |
// generic builder | |
public class Builder<T> : Builder | |
{ | |
private readonly Func<T> _ctor; | |
private readonly List<Action<T>> _configureActions = new List<Action<T>>(); | |
internal Builder(Func<T> ctor) | |
{ | |
_ctor = ctor; | |
} | |
// construct the instance to be built: calls the constructor and all configured actions | |
public T Instance | |
{ | |
get | |
{ | |
var instance = _ctor(); | |
foreach (var configure in _configureActions) | |
{ | |
configure(instance); | |
} | |
return instance; | |
} | |
} | |
public Builder<T> With(Action<T> action) | |
{ | |
_configureActions.Add(action); | |
return this; | |
} | |
} | |
#region examples | |
public static class ProductBuilder | |
{ | |
// use extension methods to provide more expressive convenience builder functions | |
public static Builder<Product> Named(this Builder<Product> builder, string name) | |
{ | |
return builder.With(p => p.Name = name); | |
} | |
// use static factory methods to construct objects with preconfigured defaults | |
public static Builder<Product> DefaultProduct() | |
{ | |
return Builder.For<Product>().Named("My Product").With(p => p.UnitPrice = 10); | |
} | |
} | |
class Order | |
{ | |
private readonly List<OrderLine> _lines; | |
public Order() | |
{ | |
Id = Guid.NewGuid().ToString(); | |
_lines = new List<OrderLine>(); | |
} | |
public Order(string id) | |
{ | |
Id = id; | |
_lines = new List<OrderLine>(); | |
} | |
public string Id { get; private set; } | |
public IEnumerable<OrderLine> Lines | |
{ | |
get { return _lines; } | |
} | |
public Customer Customer { get; set; } | |
public void AddLine(Product p, int nofItems) | |
{ | |
var orderLine = new OrderLine(p, nofItems); | |
_lines.Add(orderLine); | |
OrderTotal += orderLine.LineTotal; | |
} | |
public decimal OrderTotal { get; set; } | |
} | |
class Customer | |
{ | |
public string Name { get; set; } | |
public string Address { get; set; } | |
} | |
class OrderLine | |
{ | |
public OrderLine(Product product, int nofItems) | |
{ | |
Product = product; | |
NumberOfItems = nofItems; | |
LineTotal = product.UnitPrice * nofItems; | |
} | |
public decimal LineTotal { get; private set; } | |
public Product Product { get; private set; } | |
public int NumberOfItems { get; private set; } | |
} | |
public class Product | |
{ | |
public string Name { get; set; } | |
public decimal UnitPrice { get; set; } | |
} | |
public class Examples | |
{ | |
public void TestMethod() | |
{ | |
var product = ProductBuilder.DefaultProduct().Named("Another product").Instance; | |
int nofItems = 3; | |
var order = Builder.For<Order>().Instance; | |
order.AddLine(product, nofItems); | |
Assert.AreEqual(15, order.OrderTotal); | |
} | |
} | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment