自定义CustomBuilder实现复杂类的构建(链式)


前言

在实际开发中,构建复杂的对象往往需要多个步骤和参数。为了简化这一过程并提高代码的可读性和可维护性,本文将详细介绍如何通过一个自定义的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 模式简化了复杂对象的创建过程,提高了代码的可读性和可维护性。希望本文对您有所帮助,如果您有任何疑问或建议,欢迎留言交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值