我将流利的api与其创建的对象分开放置到它自己的“ builder”类中。这样,如果客户端不想使用流利的api,您仍然可以手动使用它,并且不会污染域对象(遵循单一职责原则)。在这种情况下,将创建以下内容:
Car
这是领域对象
CarBuilder
拥有流畅的API
用法如下:
var car = CarBuilder.BuildCar()
.OfBrand(Brand.Ford)
.OfModel(12345)
.PaintedIn(Color.Silver)
.Build();
该CarBuilder
班是这样的(我在这里使用C#命名约定):
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;
}
}
请注意,此类并非线程安全的(每个线程将需要它自己的CarBuilder实例)。还应注意,即使流利的api是一个非常酷的概念,但对于创建简单的域对象而言,它可能是过大的。
如果您要为更抽象的内容创建API,并且设置和执行更为复杂,那么这笔交易会更有用,这就是为什么它在单元测试和DI框架中表现出色的原因。您可以在Wikipedia Fluent接口文章的Java部分下看到一些其他示例,这些示例具有持久性,日期处理和模拟对象。
编辑:
从评论中注意到;您可以将Builder类设为静态内部类(在Car内部),并且Car可以不可变。让Car一成不变的这个例子似乎有点愚蠢。但是在更复杂的系统中,您绝对不想更改所构建对象的内容,那么您可能想要这样做。
下面是一个示例,说明如何同时执行静态内部类以及如何处理其构建的不可变对象的创建:
// 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();
}
}
用法如下:
var writer = ImmutableWriter
.GetBuilder()
.Write("peanut butter jelly time")
.Times(2)
.Build();
writer.Perform();
// console writes: peanut butter jelly time peanut butter jelly time
编辑2:皮特(Pete)在评论中发表了一篇博客文章,内容涉及在使用复杂域对象编写单元测试的上下文中使用具有lambda函数的构建器。这是使构建者更具表现力的一种有趣的替代方法。
在这种情况下,CarBuilder
您需要使用以下方法:
public static Car Build(Action<CarBuilder> buildAction = null) {
var carBuilder = new CarBuilder();
if (buildAction != null) buildAction(carBuilder);
return carBuilder._car;
}
可以这样使用:
Car c = CarBuilder
.Build(car =>
car.OfBrand(Brand.Ford)
.OfModel(12345)
.PaintedIn(Color.Silver);
var car = new Car(Brand.Ford, 12345, Color.Silver);
?