这GenericBuilder
构建可变对象(不可变对象将在后面讨论)的想法是使用对应构建的实例的 setter 的方法引用。这就引出了一个通用的构建器,它能够使用默认构造函数构建每个POJO - 一个构建器来统治它们;-)
实现是这样的:
public class GenericBuilder<T> {
private final Supplier<T> instantiator;
private List<Consumer<T>> instanceModifiers = new ArrayList<>();
public GenericBuilder(Supplier<T> instantiator) {
this.instantiator = instantiator;
}
public static <T> GenericBuilder<T> of(Supplier<T> instantiator) {
return new GenericBuilder<T>(instantiator);
}
public <U> GenericBuilder<T> with(BiConsumer<T, U> consumer, U value) {
Consumer<T> c = instance -> consumer.accept(instance, value);
instanceModifiers.add(c);
return this;
}
public T build() {
T value = instantiator.get();
instanceModifiers.forEach(modifier -> modifier.accept(value));
instanceModifiers.clear();
return value;
}
}
生成器是使用创建新实例的供应商构建的,然后通过使用该方法指定的修改来修改这些实例。with
将用于如下:GenericBuilder
Person
Person value = GenericBuilder.of(Person::new)
.with(Person::setName, "Otto").with(Person::setAge, 5).build();
属性和其他用法
但是,还有更多关于该建筑商的信息需要发现。
例如,上面的实现清除了修饰符。这可以移动到它自己的方法中。因此,构建器将在修改之间保持其状态,并且很容易创建多个相等的实例。或者,根据 的性质,不同对象的列表。例如,可以从递增计数器读取其值。instanceModifier
instanceModifier
继续这个想法,我们可以实现一个方法,该方法将返回调用它的实例的新克隆。这很容易实现,因为构建器的状态只是 和 的列表。从那时起,两个建筑商都可以用其他一些来改变。它们将共享相同的基础,并在构建的实例上设置一些额外的状态。fork
GenericBuilder
instantiator
instanceModifiers
instanceModifiers
最后一点我认为在需要重型实体进行企业应用程序中的单元甚至集成测试时特别有用。实体不会有神的对象,而是建造者。
也可以替代需要不同测试值的工厂。在我当前的项目中,有许多工厂用于创建测试实例。代码与不同的测试方案紧密耦合,并且很难提取测试工厂的部分内容,以便在方案略有不同的另一个测试工厂中重用。有了 ,重用这变得容易得多,因为只有一个特定的列表。GenericBuilder
GenericBuilder
instanceModifiers
若要验证创建的实例是否有效,可以使用一组谓词初始化 ,这些谓词在运行所有谓词后在方法中进行验证。GenericBuilder
build
instanceModifiers
public T build() {
T value = instantiator.get();
instanceModifiers.forEach(modifier -> modifier.accept(value));
verifyPredicates(value);
instanceModifiers.clear();
return value;
}
private void verifyPredicates(T value) {
List<Predicate<T>> violated = predicates.stream()
.filter(e -> !e.test(value)).collect(Collectors.toList());
if (!violated.isEmpty()) {
throw new IllegalStateException(value.toString()
+ " violates predicates " + violated);
}
}
不可变对象创建
要使用上述方案创建不可变对象,请将不可变对象的状态提取到可变对象中,并使用实例生成器和生成器对可变状态对象进行操作。然后,添加一个函数,该函数将为可变状态创建新的不可变实例。但是,这要求不可变对象要么像这样封装其状态,要么以这种方式进行更改(基本上将参数对象模式应用于其构造函数)。
这在某种程度上与java-8之前的构建器使用不同。在那里,构建器本身就是在末尾创建新实例的可变对象。现在,我们将构建器在可变对象中保持的状态与构建器功能本身分开。
实质上
停止编写样板构建器模式,并使用 .GenericBuilder