前言
在实际开发中,构建复杂的对象往往需要多个步骤和参数。为了简化这一过程并提高代码的可读性和可维护性,本文将详细介绍如何通过一个自定义的CustomBuilder 类,通过链式调用、分离对象的构建和展示等方式来简化代码。
提示:以下是本篇文章正文内容,下面案例可供参考
一、CustomBuilder类是什么?
- 主要功能:CustomBuilder 类主要用于构建复杂的对象,通过链式调用的方式设置对象的各种属性。
- 设计目的:简化对象的创建过程,提高代码的可读性和可维护性。
二、代码示例
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
import com.google.common.collect.Lists;
/**
* 一个通用的构建器类,用于创建和配置对象。
* @param <T> 要构建的对象类型
*/
public class CustomBuilder<T> {
// 对象实例化器,用于创建对象实例
private final Supplier<T> instantiator;
// 存储一系列修改对象的消费者
private List<Consumer<T>> modifiers = Lists.newArrayList();
/**
* 构造函数,初始化对象实例化器
* @param instantiator 用于创建对象实例的供应商
*/
private CustomBuilder(Supplier<T> instantiator){
this.instantiator = instantiator;
}
/**
* 静态工厂方法,用于创建 CustomBuilder 实例
* @param instantiator 用于创建对象实例的供应商
* @return 新的 CustomBuilder 实例
*/
public static <T> CustomBuilder<T> create(Supplier<T> instantiator){
return new CustomBuilder<T>(instantiator);
}
/**
* 添加一个单参数的修改操作
* @param consumer 修改操作的消费者
* @param p1 修改操作的第一个参数
* @return 当前的 CustomBuilder 实例
*/
public <P1> CustomBuilder<T> with(Consumer1<T, P1> consumer, P1 p1) {
// 将单参数消费者包装成普通消费者
Consumer<T> c = instance -> consumer.accept(instance, p1);
// 将消费者添加到修改列表中
modifiers.add(c);
// 返回当前的 CustomBuilder 实例,支持链式调用
return this;
}
/**
* 添加一个双参数的修改操作
* @param consumer 修改操作的消费者
* @param p1 修改操作的第一个参数
* @param p2 修改操作的第二个参数
* @return 当前的 CustomBuilder 实例
*/
public <P1, P2> CustomBuilder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2) {
// 将双参数消费者包装成普通消费者
Consumer<T> c = instance -> consumer.accept(instance, p1, p2);
// 将消费者添加到修改列表中
modifiers.add(c);
// 返回当前的 CustomBuilder 实例,支持链式调用
return this;
}
/**
* 添加一个三参数的修改操作
* @param consumer 修改操作的消费者
* @param p1 修改操作的第一个参数
* @param p2 修改操作的第二个参数
* @param p3 修改操作的第三个参数
* @return 当前的 CustomBuilder 实例
*/
public <P1, P2, P3> CustomBuilder<T> with(Consumer3<T, P1, P2, P3> consumer, P1 p1, P2 p2, P3 p3) {
// 将三参数消费者包装成普通消费者
Consumer<T> c = instance -> consumer.accept(instance, p1, p2, p3);
// 将消费者添加到修改列表中
modifiers.add(c);
// 返回当前的 CustomBuilder 实例,支持链式调用
return this;
}
/**
* 构建并返回对象实例
* @return 构建好的对象实例
*/
public T build() {
// 创建一个新的对象实例
T value = instantiator.get();
// 应用所有修改操作
modifiers.forEach(modifier -> modifier.accept(value));
// 清空修改列表,以便下次调用 build 时重新应用修改
modifiers.clear();
// 返回构建好的对象实例
return value;
}
/**
* 单参数消费者接口
* @param <T> 对象类型
* @param <P1> 第一个参数类型
*/
@FunctionalInterface
public interface Consumer1<T, P1> {
void accept(T t, P1 p1);
}
/**
* 双参数消费者接口
* @param <T> 对象类型
* @param <P1> 第一个参数类型
* @param <P2> 第二个参数类型
*/
@FunctionalInterface
public interface Consumer2<T, P1, P2> {
void accept(T t, P1 p1, P2 p2);
}
/**
* 三参数消费者接口
* @param <T> 对象类型
* @param <P1> 第一个参数类型
* @param <P2> 第二个参数类型
* @param <P3> 第三个参数类型
*/
@FunctionalInterface
public interface Consumer3<T, P1, P2, P3> {
void accept(T t, P1 p1, P2 p2, P3 p3);
}
}
三、代码分析
构造方法
private CustomBuilder(Supplier<T> instantiator)
:私有构造方法,接受一个Supplier
对象,用于创建最终的对象实例。
静态工厂方法
public static <T> CustomBuilder<T> create(Supplier<T> instantiator)
:提供一个静态工厂方法,方便获取CustomBuilder
实例。- 作用:创建
CustomBuilder
实例,并传入Supplier
对象。 - 调用示例:
CustomBuilder<MyObject> builder = CustomBuilder.create(MyObject::new);
- 作用:创建
设置属性的方法
-
public <P1> CustomBuilder<T> with(Consumer1<T, P1> consumer, P1 p1)
:- 作用:通过
Consumer1
接口设置一个参数的属性。 - 调用示例:
builder.with((obj, value) -> obj.setProperty1(value), "value1");
- 作用:通过
-
public <P1, P2> CustomBuilder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2)
:- 作用:通过
Consumer2
接口设置两个参数的属性。 - 调用示例:
builder.with((obj, value1, value2) -> obj.setProperties(value1, value2), "value1", 123);
- 作用:通过
-
public <P1, P2, P3> CustomBuilder<T> with(Consumer3<T, P1, P2, P3> consumer, P1 p1, P2 p2, P3 p3)
:- 作用:通过
Consumer3
接口设置三个参数的属性。 - 调用示例:
builder.with((obj, value1, value2, value3) -> obj.setProperties(value1, value2, value3), "value1", 123, true);
- 作用:通过
构建最终对象的方法
public T build()
:- 作用:根据内部状态创建并返回最终的对象。
- 调用示例:
MyObject myObject = builder.build();
内部机制
- 状态管理:
CustomBuilder
类通过List<Consumer<T>> modifiers
管理对象的属性设置操作。 - 链式调用:每个设置属性的方法都返回
this
,支持链式调用,使代码更加简洁和易读。
四、设计模式
- 设计模式:
CustomBuilder
类采用了 Builder 模式。 - 选择理由:Builder 模式适用于需要构建复杂对象的场景,通过分离对象的构建过程和表示,提高代码的灵活性和可读性。
- 优势:
- 分离构建过程和表示:使代码更加模块化,便于维护。
- 链式调用:使代码更加简洁和易读。
- 避免构造方法参数过多:通过多个设置方法逐步构建对象,避免构造方法参数过多的问题。
常见问题与解决方案
-
问题1:如何处理必填属性?
- 解决方案:在
build
方法中检查必填属性是否已设置,如果没有设置则抛出异常。 - 示例:
public T build() { T value = instantiator.get(); modifiers.forEach(modifier -> modifier.accept(value)); if (value.getProperty1() == null) { throw new IllegalStateException("property1 must be set"); } modifiers.clear(); return value; }
- 解决方案:在
-
问题2:如何扩展
CustomBuilder
类?- 解决方案:通过继承
CustomBuilder
类,添加新的属性和方法。 - 示例:
public class ExtendedBuilder<T> extends CustomBuilder<T> { private String extendedProperty; public ExtendedBuilder(Supplier<T> instantiator) { super(instantiator); } public ExtendedBuilder<T> withExtendedProperty(String extendedProperty) { this.extendedProperty = extendedProperty; return this; } @Override public T build() { T value = super.build(); // 扩展后的构建逻辑 value.setExtendedProperty(extendedProperty); return value; } }
- 解决方案:通过继承
-
问题3:提供添加一个任意参数数量的修改操作(笔者只是回答问题,这个任意参数的方法暂时没有用于企业编码,短期没有实践诉求,请读者自己注意,如果你应用了,应用之后可以后续在评论区反馈)
- 示例:
/** * 添加一个任意参数数量的修改操作 * @param methodName 修改操作的方法名 * @param args 修改操作的参数 * @return 当前的 CustomBuilder 实例 */ public CustomBuilder<T> with(String methodName, Object... args) { // 使用反射创建消费者 Consumer<T> c = (instance) -> { try { // 获取方法 Method method = instance.getClass().getMethod(methodName, getParameterTypes(args)); // 调用方法 method.invoke(instance, args); } catch (Exception e) { throw new RuntimeException("Failed to invoke method: " + methodName, e); } }; // 将消费者添加到修改列表中 modifiers.add(c); // 返回当前的 CustomBuilder 实例,支持链式调用 return this; }
- 示例:
-
问题4:如何使用
- 示例:
CustomBuilder.create(XXObject::new).build(); CustomBuilder.create(XXObject::new).with(XXObject::setXXProperties1,param1).build(); CustomBuilder.create(XXObject::new).with(XXObject::setXXProperties2,param1,param2).build(); CustomBuilder.create(XXObject::new).with(XXObject::setXXProperties3,param1,param2,param3).build();
- 示例:
结语
CustomBuilder
类通过 Builder 模式简化了复杂对象的创建过程,提高了代码的可读性和可维护性。希望本文对您有所帮助,如果您有任何疑问或建议,欢迎留言交流。