「 现象 」
封装业务对象的时候,需要设置业务的值,单个SetXX看起来还行,但是对于复杂对象设置多个属性和对于多个部件一步一步创建时候,那就是一顿操作SetXX,之后会出现通天塔楼层结构。外部提供的jar包想用构建者能力,但是没有权限修改调整,有时候还会出现不同地方的设置值。基于此,探索出流式处理封装构建者增强原有对象的功能,尽量达成一气呵成。
§ 1.支持功能
🔹 支持基础链式设置值
🔹 支持函数基础链式设置值 ()→ t 、t → t
🔹 支持if-set、if-do-set的链式设置封装
🔹 支持if-else-set、if-do-else-set的链式设置封装
🔹 封装不同数据类型判断的语法糖
🔹 支持值在流中传递处理设置
§ 2.通用流式构建工具
先由of
方法设置实例化器instantiator
来创建一个后续需要流式构建的对象,之后可以开始流式设置值。对于某些需要判断的条件支持基础的boolean和Predicate
来判断条件,条件之后可以进行if-do的处理或者if-else-do的处理, do方面支持UnaryOperator
(()→ t)和Supplier
(t → t)来对于数据二次处理。在流中设置的值的需求也可以使用withFlush
来对传递的值做传递处理,支持值的多次加工操作,最后通过build()
来设置所有的修改值封装对象。
import java.util.ArrayList;
import java.util.List;
import java.util.function.*;
/**
* 通用构建模式构建器
*
* @author jinmai
* @date 2022/9/5
*/
public class Builder<T> {
/**
* 实例化器
*/
private final Supplier<T> instantiator;
/**
* 修改类集合
*/
private List<Consumer<T>> modifiers = new ArrayList<>();
/**
* 通用构建器构造方法
*
* @param instantiator 实例化器
*/
public Builder(Supplier<T> instantiator) {
this.instantiator = instantiator;
}
/**
* 静态初始化实例
*
* @param instantiator 实例容器
* @param <T> 实例化器
* @return 构建器
*/
public static <T> Builder<T> of(Supplier<T> instantiator) {
return new Builder<>(instantiator);
}
/**
* 构建一个入参设置方法
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> with(BiConsumer<T, P1> consumer, P1 p1) {
Consumer<T> c = instance -> consumer.accept(instance, p1);
modifiers.add(c);
return this;
}
/**
* 构建值传递处理方式
* @param consumer 指定操作方法
* @param function 获取传递值二次处理
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> withFlush(BiConsumer<T, P1> consumer, Function<T,P1> function) {
Consumer<T> c = instance -> {
P1 p1 = function.apply(instance);
if (p1 != null) {
consumer.accept(instance, p1);
}
};
modifiers.add(c);
return this;
}
/**
* 构建一个入参设置方法
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param op 数据操作 t->t
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> with(BiConsumer<T, P1> consumer, P1 p1,UnaryOperator<P1> op) {
Consumer<T> c = instance -> consumer.accept(instance, op.apply(p1));
modifiers.add(c);
return this;
}
/**
* 构建一个入参设置方法
*
* @param consumer 指定操作方法
* @param op 数据操作 ()->t
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> with(BiConsumer<T, P1> consumer, Supplier<P1> op) {
Consumer<T> c = instance -> consumer.accept(instance, op.get());
modifiers.add(c);
return this;
}
/**
* 满足条件,构建一个入参设置方法
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> with(boolean condition, BiConsumer<T, P1> consumer, P1 p1) {
if (condition) {
Consumer<T> c = instance -> consumer.accept(instance, p1);
modifiers.add(c);
}
return this;
}
/**
* 判断条件,构建入参数设置方法
* @param predicate 判断条件
* @param consumer 指定操作方法
* @param p1 入参数
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> with(Predicate<? super P1> predicate, BiConsumer<T, P1> consumer, P1 p1) {
if (predicate.test(p1)) {
Consumer<T> c = instance -> consumer.accept(instance, p1);
modifiers.add(c);
}
return this;
}
/**
* 判断条件,构建入参数设置方法
* @param predicate 判断条件
* @param consumer 指定操作方法
* @param p1 入参数
* @param op 数据操作 t->t
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> with(Predicate<? super P1> predicate, BiConsumer<T, P1> consumer, P1 p1, UnaryOperator<P1> op) {
if (predicate.test(p1)) {
Consumer<T> c = instance -> consumer.accept(instance, op.apply(p1));
modifiers.add(c);
}
return this;
}
/**
* 判断条件,构建入参数设置方法
* @param predicate 判断条件
* @param consumer 指定操作方法
* @param p1 入参数
* @param op 数据操作 ()->t
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> with(Predicate<? super P1> predicate, BiConsumer<T, P1> consumer, P1 p1, Supplier<P1> op) {
if (predicate.test(p1)) {
Consumer<T> c = instance -> consumer.accept(instance, op.get());
modifiers.add(c);
}
return this;
}
/**
* 判断表达式执行处理回调{@link Handler}
* @param expression 判断表达式
* @return 返回执行回调处理方式
*/
public Handler<T> withIf(boolean expression){
return (trueHandler, falseHandler) -> expression?trueHandler.apply(this):falseHandler.apply(this);
}
/**
* 满足条件,构建一个入参设置方法
* 变种1.1:判断数据是否为空,是空添加数据
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> withNull(BiConsumer<T, P1> consumer, P1 p1) {
return with(p1 == null, consumer, p1);
}
/**
* 满足条件,构建一个入参设置方法
* 变种1.2:判断数据是否不是为空,不是是空添加数据
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> withNonNull(BiConsumer<T, P1> consumer, P1 p1) {
return with(p1 != null, consumer, p1);
}
/**
* 满足条件,构建一个入参设置方法
* 变种1.3:判断数据是否为空,是空对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param op 数据处理方法
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> withNull(BiConsumer<T, P1> consumer, P1 p1, UnaryOperator<P1> op) {
return with(p1 == null, consumer, op.apply(p1));
}
/**
* 满足条件,构建一个入参设置方法
* 变种1.4:判断数据是否不是为空,不是是空对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param op 数据处理方法
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> withNonNull(BiConsumer<T, P1> consumer, P1 p1, UnaryOperator<P1> op) {
return with(p1 != null, consumer, op.apply(p1));
}
/**
* 满足条件,构建一个入参设置方法
* 变种1.5:判断数据是否为空,是空对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param op 数据处理方法 ()->t
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> withNull(BiConsumer<T, P1> consumer, P1 p1, Supplier<P1> op) {
return with(p1 == null, consumer, op.get());
}
/**
* 满足条件,构建一个入参设置方法
* 变种1.6:判断数据是否不是为空,不是是空对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 入参数
* @param op 数据处理方法 ()->t
* @param <P1> 第一个参数泛型
* @return 构建器
*/
public <P1> Builder<T> withNonNull(BiConsumer<T, P1> consumer, P1 p1, Supplier<P1> op) {
return with(p1 != null, consumer, op.get());
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.1:判断数据是否为空,是空添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @return 构建器
*/
public Builder<T> withIsEmpty(BiConsumer<T, String> consumer, String p1) {
boolean predicate = p1 == null || p1.length() == 0;
return with(predicate, consumer, p1);
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.2:判断数据是否不为空,不是空添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @return 构建器
*/
public Builder<T> withIsNotEmpty(BiConsumer<T, String> consumer, String p1) {
boolean predicate = p1 == null || p1.length() == 0;
return with(!predicate, consumer, p1);
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.3:判断数据是否为空字符串,是空字符串添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @return 构建器
*/
public Builder<T> withIsBlank(BiConsumer<T, String> consumer, String p1) {
return with(Builder::isBlank, consumer, p1);
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.4:判断数据是否不为空字符串,不是空字符串添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @return 构建器
*/
public Builder<T> withIsNotBlank(BiConsumer<T, String> consumer, String p1) {
return with(Builder::isNotBlank, consumer, p1);
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.5:判断数据是否为空,是空添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法
* @return 构建器
*/
public Builder<T> withIsEmpty(BiConsumer<T, String> consumer, String p1, UnaryOperator<String> op) {
boolean predicate = p1 == null || p1.length() == 0;
return with(predicate, consumer, op.apply(p1));
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.6:判断数据是否不为空,不是空对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法
* @return 构建器
*/
public Builder<T> withIsNotEmpty(BiConsumer<T, String> consumer, String p1, UnaryOperator<String> op) {
boolean predicate = p1 == null || p1.length() == 0;
return with(!predicate, consumer, op.apply(p1));
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.7:判断数据是否为空字符串,是空字符串对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法
* @return 构建器
*/
public Builder<T> withIsBlank(BiConsumer<T, String> consumer, String p1, UnaryOperator<String> op) {
return with(Builder::isBlank, consumer, op.apply(p1));
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.8:判断数据是否不为空字符串,不是空字符串对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法
* @return 构建器
*/
public Builder<T> withIsNotBlank(BiConsumer<T, String> consumer, String p1, UnaryOperator<String> op) {
return with(Builder::isNotBlank, consumer, op.apply(p1));
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.9:判断数据是否为空,是空添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法 ()->t
* @return 构建器
*/
public Builder<T> withIsEmpty(BiConsumer<T, String> consumer, String p1, Supplier<String> op) {
boolean predicate = p1 == null || p1.length() == 0;
return with(predicate, consumer, op.get());
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.10:判断数据是否不为空,不是空对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法 ()->t
* @return 构建器
*/
public Builder<T> withIsNotEmpty(BiConsumer<T, String> consumer, String p1, Supplier<String> op) {
boolean predicate = p1 == null || p1.length() == 0;
return with(!predicate, consumer, op.get());
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.11:判断数据是否为空字符串,是空字符串对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法 ()->t
* @return 构建器
*/
public Builder<T> withIsBlank(BiConsumer<T, String> consumer, String p1, Supplier<String> op) {
return with(Builder::isBlank, consumer, op.get());
}
/**
* 满足条件,构建一个入参设置方法
* 变种2.12:判断数据是否不为空字符串,不是空字符串对数据二次加工并添加数据
*
* @param consumer 指定操作方法
* @param p1 字符串入参
* @param op 数据处理方法
* @return 构建器
*/
public Builder<T> withIsNotBlank(BiConsumer<T, String> consumer, String p1, Supplier<String> op) {
return with(Builder::isNotBlank, consumer, op.get());
}
/**
* 构建两个入参设置方法
*
* @param consumer 指定操作方法
* @param p1 第一个参数
* @param p2 第二个参数
* @param <P1> 第一个参数泛型
* @param <P2> 第二个参数泛型
* @return 构建器
*/
public <P1, P2> Builder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2) {
Consumer<T> c = instance -> consumer.accept(instance, p1, p2);
modifiers.add(c);
return this;
}
/**
* 构建三个入参设置方法
*
* @param consumer 指定操作方法
* @param p1 第一个参数
* @param p2 第二个参数
* @param p3 第三个参数
* @param <P1> 第一个参数泛型
* @param <P2> 第二个参数泛型
* @param <P3> 第三个参数泛型
* @return 构建器
*/
public <P1, P2, P3> Builder<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);
return this;
}
/**
* 组装数据
*
* @return 构建器
*/
public T build() {
T value = instantiator.get();
modifiers.forEach(modifiers -> modifiers.accept(value));
modifiers.clear();
return value;
}
/**
* 实例2个参数操作函数式方法接口
*
* @param <T> 实例
* @param <P1> 第一个输入参数
* @param <P2> 第二个输入参数
*/
@FunctionalInterface
public interface Consumer2<T, P1, P2> {
/**
* 对给定两个参数执行该操作
*
* @param t 实例对象
* @param p1 第一个输入参数
* @param p2 第二个输入参数
*/
void accept(T t, P1 p1, P2 p2);
}
/**
* 实例3个参数操作函数式方法接口
*
* @param <T> 实例
* @param <P1> 第一个输入参数
* @param <P2> 第二个输入参数
*/
@FunctionalInterface
public interface Consumer3<T, P1, P2, P3> {
/**
* 对给定三个参数执行该操作
*
* @param t 实例对象
* @param p1 第一个输入参数
* @param p2 第二个输入参数
* @param p3 第三个输入参数
*/
void accept(T t, P1 p1, P2 p2, P3 p3);
}
/**
* 选择做什么事情
* @param <T> 泛型
*/
public interface Handler<T>{
Builder<T> doIt(UnaryOperator<Builder<T>> trueBuilder,UnaryOperator<Builder<T>> falseBuilder);
}
/**
* 不是空字符串
* @param cs 字符
* @return 是否不是空字符串
*/
public static boolean isNotBlank(CharSequence cs) {
return !isBlank(cs);
}
/**
* 是否空字符串为空白字符,空白符包含:空格、tab键、换行符
* @param cs 字符
* @return 字符串是否为空白字符
*/
public static boolean isBlank(CharSequence cs) {
int strLen = length(cs);
if (strLen == 0) {
return true;
} else {
for(int i = 0; i < strLen; ++i) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
}
/**
* 字符串长度
* @param cs
* @return 字符串长度
*/
public static int length(CharSequence cs) {
return cs == null ? 0 : cs.length();
}
}
§ 3.如果使用
新建一个测试类Category来测试封装构建的所有信息数据,测试字符串、数值和集合类型对于上述功能的测试功能是否支持,并不一定强制流方式处理,也可以拆分细流,最后通过build()
汇总所有的细流来构建对象
@Test
public void testBuilder(){
//基础数据准备
List<Category> children = new ArrayList<>();
String name = "";
String nameEn = " ";
String nameRel = "today";
Long id = 12L;
//数据封装
Category category = Builder.of(Category::new)
//基础设置值
.with(Category::setChildren, children)
//集合的处理(if-set处理)
.with(CollectionUtils::isNotEmpty, Category::setChildren, children)
//单独非空值处理(if-set处理)
.with(Objects::nonNull, Category::setId, id)
//字符串非空字符串语法糖(if-set处理)
.withIsNotBlank(Category::setName, name)
//字符串非空字符串数据二次处理语法糖(if-do-set处理 t -> t)
.withIsBlank(Category::setNameEn, nameEn, _name -> _name + "TestEn")
//字符串非空字符串数据二次处理语法糖(if-do-set处理 ()->t)
.withIsBlank(Category::setNameEn, nameEn, () -> "TestEn")
//字符串非空字符串数据二次处理语法糖(if-do-set处理 t -> t)
.withIsEmpty(Category::setNameRel, nameRel, _name -> _name + "TestRelIsEmpty")
//数据判断处理(if-else-do-set处理) x表示的还是builder对象,上面功能还能嵌套进来
.withIf(nameRel == "today").doIt(
x -> x.with(Category::setNameRel, "TestTh1", _name -> _name + "TestTh1"),
x -> x.with(Category::setNameRel, "TestTh2", _name -> _name + "TestTh2"))
.withIsEmpty(Category::setNameRel, nameRel, _name -> _name + "TestRelIsEmpty2")
//值流传递处理
.withFlush(Category::setNameEn, x -> x.getId() + "")
.build();
//输入数据
System.out.println(JSON.toJSONString(category));
}
/**
* 测试基础类目
*/
@Data
public class Category{
private Long id;
private String name;
private String nameEn;
private String nameRel;
private List<Category> children;
}
【测试结果】
Connected to the target VM, address: '127.0.0.1:50191', transport: 'socket'
{"children":[],"id":12,"nameEn":"12","nameRel":"TestTh1TestTh1"}