diff --git a/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java b/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java new file mode 100644 index 000000000..3046427bd --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/builder/GenericBuilder.java @@ -0,0 +1,478 @@ +package cn.hutool.core.builder; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + *

通用Builder

+ * 参考: 一看就会的java8通用Builder + *

使用方法如下:

+ *
+ * Box box = GenericBuilder
+ * 		.of(Box::new)
+ * 		.with(Box::setId, 1024L)
+ * 		.with(Box::setTitle, "Hello World!")
+ * 		.with(Box::setLength, 9)
+ * 		.with(Box::setWidth, 8)
+ * 		.with(Box::setHeight, 7)
+ * 		.build();
+ *
+ * 
+ * + *

我们也可以对已创建的对象进行修改:

+ *
+ * Box boxModified = GenericBuilder
+ * 		.of(() -> box)
+ * 		.with(Box::setTitle, "Hello Friend!")
+ * 		.with(Box::setLength, 3)
+ * 		.with(Box::setWidth, 4)
+ * 		.with(Box::setHeight, 5)
+ * 		.build();
+ * 
+ *

我们还可以对这样调用有参构造,这对于创建一些在有参构造中包含初始化函数的对象是有意义的:

+ *
+ * Box box1 = GenericBuilder
+ * 		.of(Box::new, 2048L, "Hello Partner!", 222, 333, 444)
+ * 		.with(Box::alis)
+ * 		.build();
+ * 
+ *

注意:本工具类支持调用的方法的参数数量不超过5个,更多的参数不利于阅读和维护。 + * 关于Java方法的参数个数限制似乎并没有明确统一的规范,网络上众说纷纭,这里取个相对平均的数5。 + * 特殊需要求可以基于此类进行拓展. + *

+ * + * @author TomXin + * @since jdk1.8 + */ +public class GenericBuilder implements Builder { + + /** + * 实例化器 + */ + private final Supplier instantiator; + + /** + * 修改器列表 + */ + private final List> modifiers = new ArrayList<>(); + + /** + * 构造 + * + * @param instant 实例化器 + */ + public GenericBuilder(Supplier instant) { + this.instantiator = instant; + } + + /** + * 通过无参数实例化器创建GenericBuilder + * + * @param instant 实例化器 + * @param 目标类型 + * @return GenericBuilder对象 + */ + public static GenericBuilder of(Supplier instant) { + return new GenericBuilder<>(instant); + } + + /** + * 通过1参数实例化器创建GenericBuilder + * + * @param instant 实例化器 + * @param p1 参数一 + * @param 目标类型 + * @param 参数一类型 + * @return GenericBuilder对象 + */ + public static GenericBuilder of(Supplier1 instant, P1 p1) { + Supplier s = () -> instant.get(p1); + return new GenericBuilder<>(s); + } + + /** + * 通过2参数实例化器创建GenericBuilder + * + * @param instant 实例化器 + * @param p1 参数一 + * @param p2 参数二 + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + * @return GenericBuilder对象 + */ + public static GenericBuilder of(Supplier2 instant, P1 p1, P2 p2) { + Supplier s = () -> instant.get(p1, p2); + return new GenericBuilder<>(s); + } + + /** + * 通过3参数实例化器创建GenericBuilder + * + * @param instant 实例化器 + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @return GenericBuilder对象 + */ + public static GenericBuilder of(Supplier3 instant, P1 p1, P2 p2, P3 p3) { + Supplier s = () -> instant.get(p1, p2, p3); + return new GenericBuilder<>(s); + } + + /** + * 通过4参数实例化器创建GenericBuilder + * + * @param instant 实例化器 + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @param 参数四类型 + * @return GenericBuilder对象 + */ + public static GenericBuilder of(Supplier4 instant, P1 p1, P2 p2, P3 p3, P4 p4) { + Supplier s = () -> instant.get(p1, p2, p3, p4); + return new GenericBuilder<>(s); + } + + /** + * 通过5参数实例化器创建GenericBuilder + * + * @param instant 实例化器 + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + * @param p5 参数五 + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @param 参数四类型 + * @param 参数五类型 + * @return GenericBuilder对象 + */ + public static GenericBuilder of(Supplier5 instant, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { + Supplier s = () -> instant.get(p1, p2, p3, p4, p5); + return new GenericBuilder<>(s); + } + + + /** + * 调用无参数方法 + * + * @param consumer 无参数Consumer + * @return GenericBuilder对象 + */ + public GenericBuilder with(Consumer consumer) { + modifiers.add(consumer); + return this; + } + + + /** + * 调用1参数方法 + * + * @param consumer 1参数Consumer + * @param p1 参数一 + * @param 参数一类型 + * @return GenericBuilder对象 + */ + public GenericBuilder with(Consumer1 consumer, P1 p1) { + Consumer c = instance -> consumer.accept(instance, p1); + modifiers.add(c); + return this; + } + + /** + * 调用2参数方法 + * + * @param consumer 2参数Consumer + * @param p1 参数一 + * @param p2 参数二 + * @param 参数一类型 + * @param 参数二类型 + * @return GenericBuilder对象 + */ + public GenericBuilder with(Consumer2 consumer, P1 p1, P2 p2) { + Consumer c = instance -> consumer.accept(instance, p1, p2); + modifiers.add(c); + return this; + } + + /** + * 调用3参数方法 + * + * @param consumer 3参数Consumer + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @return GenericBuilder对象 + */ + public GenericBuilder with(Consumer3 consumer, P1 p1, P2 p2, P3 p3) { + Consumer c = instance -> consumer.accept(instance, p1, p2, p3); + modifiers.add(c); + return this; + } + + /** + * 调用4参数方法 + * + * @param consumer 4参数Consumer + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @param 参数四类型 + * @return GenericBuilder对象 + */ + public GenericBuilder with(Consumer4 consumer, P1 p1, P2 p2, P3 p3, P4 p4) { + Consumer c = instance -> consumer.accept(instance, p1, p2, p3, p4); + modifiers.add(c); + return this; + } + + /** + * 调用5参数方法 + * + * @param consumer 5参数Consumer + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + * @param p5 参数五 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @param 参数四类型 + * @param 参数五类型 + * @return GenericBuilder对象 + */ + public GenericBuilder with(Consumer5 consumer, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { + Consumer c = instance -> consumer.accept(instance, p1, p2, p3, p4, p5); + modifiers.add(c); + return this; + } + + /** + * 构建 + * + * @return 目标对象 + */ + @Override + public T build() { + T value = instantiator.get(); + modifiers.forEach(modifier -> modifier.accept(value)); + modifiers.clear(); + return value; + } + + + /** + * 1参数Supplier + * + * @param 目标类型 + * @param 参数一类型 + */ + @FunctionalInterface + public interface Supplier1 { + /** + * 生成实例的方法 + * + * @param p1 参数一 + * @return 目标对象 + */ + T get(P1 p1); + } + + + /** + * 2参数Supplier + * + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + */ + @FunctionalInterface + public interface Supplier2 { + + /** + * 生成实例的方法 + * + * @param p1 参数一 + * @param p2 参数二 + * @return 目标对象 + */ + T get(P1 p1, P2 p2); + } + + /** + * 3参数Supplier + * + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + */ + @FunctionalInterface + public interface Supplier3 { + + /** + * 生成实例的方法 + * + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @return 目标对象 + */ + T get(P1 p1, P2 p2, P3 p3); + } + + + /** + * 4参数Supplier + * + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @param 参数四类型 + */ + @FunctionalInterface + public interface Supplier4 { + + /** + * 生成实例的方法 + * + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + * @return 目标对象 + */ + T get(P1 p1, P2 p2, P3 p3, P4 p4); + } + + /** + * 5参数Supplier + * + * @param 目标类型 + * @param 参数一类型 + * @param 参数二类型 + * @param 参数三类型 + * @param 参数四类型 + * @param 参数五类型 + */ + @FunctionalInterface + public interface Supplier5 { + + /** + * 生成实例的方法 + * + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + * @param p5 参数五 + * @return 目标对象 + */ + T get(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5); + } + + /** + * 1参数Consumer + */ + @FunctionalInterface + public interface Consumer1 { + /** + * 接收参数方法 + * + * @param t 对象 + * @param p1 参数二 + */ + void accept(T t, P1 p1); + } + + /** + * 2参数Consumer + */ + @FunctionalInterface + public interface Consumer2 { + /** + * 接收参数方法 + * + * @param t 对象 + * @param p1 参数一 + * @param p2 参数二 + */ + void accept(T t, P1 p1, P2 p2); + } + + /** + * 3参数Consumer + */ + @FunctionalInterface + public interface Consumer3 { + /** + * 接收参数方法 + * + * @param t 对象 + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + */ + void accept(T t, P1 p1, P2 p2, P3 p3); + } + + /** + * 4参数Consumer + */ + @FunctionalInterface + public interface Consumer4 { + /** + * 接收参数方法 + * + * @param t 对象 + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + */ + void accept(T t, P1 p1, P2 p2, P3 p3, P4 p4); + } + + /** + * 5参数Consumer + */ + @FunctionalInterface + public interface Consumer5 { + /** + * 接收参数方法 + * + * @param t 对象 + * @param p1 参数一 + * @param p2 参数二 + * @param p3 参数三 + * @param p4 参数四 + * @param p5 参数五 + */ + void accept(T t, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/builder/GenericBuilderTest.java b/hutool-core/src/test/java/cn/hutool/core/builder/GenericBuilderTest.java new file mode 100644 index 000000000..b3753e62d --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/builder/GenericBuilderTest.java @@ -0,0 +1,69 @@ +package cn.hutool.core.builder; + +import cn.hutool.core.util.StrUtil; +import lombok.*; +import org.junit.Test; + +/** + * {@link GenericBuilder} 单元测试类 + * + * @author TomXin + */ +public class GenericBuilderTest { + + @Test + public void test() { + Box box = GenericBuilder + .of(Box::new) + .with(Box::setId, 1024L) + .with(Box::setTitle, "Hello World!") + .with(Box::setLength, 9) + .with(Box::setWidth, 8) + .with(Box::setHeight, 7) + .build(); + System.out.println(box); + Box boxModified = GenericBuilder + .of(() -> box) + .with(Box::setTitle, "Hello Friend!") + .with(Box::setLength, 3) + .with(Box::setWidth, 4) + .with(Box::setHeight, 5) + .build(); + System.out.println(boxModified); + Box box1 = GenericBuilder + .of(Box::new, 2048L, "Hello Partner!", 222, 333, 444) + .with(Box::alis) + .build(); + System.out.println(box1); + } + + @Getter + @Setter + @ToString + public static class Box { + private Long id; + private String title; + private Integer length; + private Integer width; + private Integer height; + private String titleAlias; + + public Box() { + } + + public Box(Long id, String title, Integer length, Integer width, Integer height) { + this.id = id; + this.title = title; + this.length = length; + this.width = width; + this.height = height; + } + + public void alis() { + if (StrUtil.isNotBlank(this.title)) { + this.titleAlias = "TomXin:\"" + title + "\""; + } + } + } + +}