Eu colocaria a API fluente em sua própria classe "builder" separada do objeto que está criando. Dessa forma, se o cliente não quiser usar a API fluente, você ainda poderá usá-la manualmente e não poluir o objeto de domínio (aderindo ao princípio de responsabilidade única). Nesse caso, o seguinte seria criado:
Car
qual é o objeto de domínio
CarBuilder
que contém a API fluente
O uso seria assim:
var car = CarBuilder.BuildCar()
.OfBrand(Brand.Ford)
.OfModel(12345)
.PaintedIn(Color.Silver)
.Build();
A CarBuilder
classe ficaria assim (estou usando a convenção de nomenclatura C # aqui):
public class CarBuilder {
private Car _car;
/// Constructor
public CarBuilder() {
_car = new Car();
SetDefaults();
}
private void SetDefaults() {
this.OfBrand(Brand.Ford);
// you can continue the chaining for
// other default values
}
/// Starts an instance of the car builder to
/// build a new car with default values.
public static CarBuilder BuildCar() {
return new CarBuilder();
}
/// Sets the brand
public CarBuilder OfBrand(Brand brand) {
_car.SetBrand(brand);
return this;
}
// continue with OfModel(...), PaintedIn(...), and so on...
// that returns "this" to allow method chaining
/// Returns the built car
public Car Build() {
return _car;
}
}
Observe que essa classe não será segura para threads (cada thread precisará de sua própria instância do CarBuilder). Observe também que, embora a API fluente seja um conceito muito interessante, provavelmente é um exagero com o objetivo de criar objetos de domínio simples.
Esse acordo é mais útil se você estiver criando uma API para algo muito mais abstrato e tiver configuração e execução mais complexas, e é por isso que funciona muito bem em testes de unidade e estruturas de DI. Você pode ver outros exemplos na seção Java do artigo da wikipedia Fluent Interface com objetos de persistência, manipulação de datas e simulação.
EDITAR:
Como observado nos comentários; você poderia tornar a classe Builder uma classe interna estática (dentro de Car) e Car poderia ser imutável. Este exemplo de deixar Car imutável parece um pouco tolo; mas em um sistema mais complexo, onde você absolutamente não deseja alterar o conteúdo do objeto que é criado, convém fazê-lo.
Abaixo está um exemplo de como fazer a classe interna estática e como lidar com uma criação de objeto imutável que ela constrói:
// the class that represents the immutable object
public class ImmutableWriter {
// immutable variables
private int _times; private string _write;
// the "complex" constructor
public ImmutableWriter(int times, string write) {
_times = times;
_write = write;
}
public void Perform() {
for (int i = 0; i < _times; i++) Console.Write(_write + " ");
}
// static inner builder of the immutable object
protected static class ImmutableWriterBuilder {
// the variables needed to construct the immutable object
private int _ii = 0; private string _is = String.Empty;
public void Times(int i) { _ii = i; }
public void Write(string s) { _is = s; }
// The stuff is all built here
public ImmutableWriter Build() {
return new ImmutableWriter(_ii, _is);
}
}
// factory method to get the builder
public static ImmutableWriterBuilder GetBuilder() {
return new ImmutableWriterBuilder();
}
}
O uso seria o seguinte:
var writer = ImmutableWriter
.GetBuilder()
.Write("peanut butter jelly time")
.Times(2)
.Build();
writer.Perform();
// console writes: peanut butter jelly time peanut butter jelly time
Edit 2: Pete nos comentários fez um post no blog sobre o uso de construtores com funções lambda no contexto de gravação de testes de unidade com objetos de domínio complexos. É uma alternativa interessante para tornar o construtor um pouco mais expressivo.
No caso de CarBuilder
você precisar ter esse método:
public static Car Build(Action<CarBuilder> buildAction = null) {
var carBuilder = new CarBuilder();
if (buildAction != null) buildAction(carBuilder);
return carBuilder._car;
}
Que pode ser usado assim:
Car c = CarBuilder
.Build(car =>
car.OfBrand(Brand.Ford)
.OfModel(12345)
.PaintedIn(Color.Silver);
var car = new Car(Brand.Ford, 12345, Color.Silver);
?