流式函数建造模式构建对象的探索

现象

         封装业务对象的时候,需要设置业务的值,单个SetXX看起来还行,但是对于复杂对象设置多个属性和对于多个部件一步一步创建时候,那就是一顿操作SetXX,之后会出现通天塔楼层结构。外部提供的jar包想用构建者能力,但是没有权限修改调整,有时候还会出现不同地方的设置值。基于此,探索出流式处理封装构建者增强原有对象的功能,尽量达成一气呵成。

§ 1.支持功能

    🔹 支持基础链式设置值

    🔹 支持函数基础链式设置值 () t 、t t

    🔹 支持if-set、if-do-set的链式设置封装

    🔹 支持if-else-set、if-do-else-set的链式设置封装

    🔹 封装不同数据类型判断的语法糖

    🔹 支持值在流中传递处理设置

§ 2.通用流式构建工具

        先由of方法设置实例化器instantiator来创建一个后续需要流式构建的对象,之后可以开始流式设置值。对于某些需要判断的条件支持基础的booleanPredicate来判断条件,条件之后可以进行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"}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值