Java8-Function创建对象替代Builder

以下是重新润色后的文章内容:


静态内部类实现的 Builder 模式

静态内部类实现的 Builder 模式是一种广受推崇且简洁高效的实现方式,尤其适用于构建拥有众多属性的对象。它不仅能让代码清晰易读,还能提供类型安全、默认值设置等诸多优势。

静态内部类实现的 Builder 模式

1. User 类设计

定义一个 User 类,包含多个属性以及一个私有的构造函数,通过这种方式禁止直接实例化。同时,提供一个静态内部类 Builder,用于构建 User 对象。

java 复制代码
public class User {
    private final String name;
    private final int age;
    private final String email;

    // 私有构造函数,防止直接实例化
    private User(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
        this.email = builder.email;
    }

    // Getter 方法
    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String getEmail() {
        return email;
    }

    // 静态内部类 Builder
    public static class Builder {
        private String name;
        private int age;
        private String email;

        // 构造方法
        public Builder() {}

        // 设置 name 属性
        public Builder name(String name) {
            this.name = name;
            return this;
        }

        // 设置 age 属性
        public Builder age(int age) {
            this.age = age;
            return this;
        }

        // 设置 email 属性
        public Builder email(String email) {
            this.email = email;
            return this;
        }

        // 构建 User 对象
        public User build() {
            return new User(this);
        }
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}
2. 使用示例

借助 User.Builder 来构建 User 对象,这种方式极为灵活,可根据实际需求设置属性。

java 复制代码
public class Main {
    public static void main(String[] args) {
        // 使用 Builder 构建 User 对象
        User user = new User.Builder()
                .name("张三")
                .age(25)
                .email("zhangsan@xxx.com")
                .build();

        // 输出 User 对象
        System.out.println(user);
    }
}

输出结果

复制代码
User{name='张三', age=25, email='zhangsan@xxx.com'}

优点

  1. 类型安全:通过方法链的方式设置属性,编译器会严格检查类型错误,有效避免潜在的类型问题。
  2. 可读性高:代码结构清晰,逻辑简洁明了,易于阅读和维护,即使是新接手项目的开发者也能快速理解代码逻辑。
  3. 灵活性强:可以根据实际需求有选择性地设置属性,对于不需要设置的属性可以轻松省略,不会受到任何限制。
  4. 默认值支持 :可以在 Builder 类中为属性设置默认值,方便在某些属性未被显式设置时提供合理的默认行为。

缺点

  1. 代码量稍多 :需要额外定义一个 Builder 内部类,这在一定程度上增加了代码的总量,对于一些追求极致简洁的开发者来说可能会觉得有些繁琐。
  2. 复杂度增加:对于结构简单的对象,使用这种模式可能会显得有些大材小用,增加了不必要的复杂度。

基于 Function 的 Builder 模式

核心设计思路

基于 Function 的 Builder 模式采用函数式接口封装 setter 逻辑,支持 Lambda 表达式简化调用,从而实现更加灵活、简洁的对象构建方式。其核心实现分为两个关键组件:

  • BuildFunction:定义标准的属性设置接口,为后续的属性设置操作提供规范。
  • InstanceBuilder:集成实例创建、属性配置以及校验功能,是整个模式的核心实现部分。

BuildFunction 接口

java 复制代码
@FunctionalInterface 
public interface BuildFunction<T, P> {
    /**
     * 执行属性设置
     * @param target 目标对象
     * @param param 要设置的属性值
     */
    void call(T target, P param);
}

InstanceBuilder 类

java 复制代码
import java.util.Objects;
import java.util.function.Predicate;

/**
 * 实例构建器
 * 用于构建和配置对象实例,支持链式调用设置属性值
 *
 * @param <T> 要构建的实例类型
 */
public class InstanceBuilder<T> {

    /** 正在构建的实例对象 */
    private T inst;

    /**
     * 私有构造函数 - 基于现有实例创建构建器
     *
     * @param inst 已存在的实例对象
     */
    private InstanceBuilder(T inst) {
        this.inst = Objects.requireNonNull(inst, "Instance cannot be null");
    }

    /**
     * 私有构造函数 - 基于类创建构建器(通过反射实例化)
     *
     * @param instClass 要实例化的类
     */
    private InstanceBuilder(Class<T> instClass) {
        Objects.requireNonNull(instClass, "instClass cannot be null");
        try {
            // 使用无参构造函数创建实例
            this.inst = instClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create instance of " + instClass.getName(), e);
        }
    }

    /**
     * 静态工厂方法 - 基于现有实例创建构建器
     *
     * @param <T> 实例类型
     * @param inst 已存在的实例对象
     * @return InstanceBuilder实例
     */
    public static <T> InstanceBuilder<T> of(T inst){
        return new InstanceBuilder<>(inst);
    }

    /**
     * 静态工厂方法 - 基于类创建构建器
     *
     * @param <T> 实例类型
     * @param instClass 要实例化的类
     * @return InstanceBuilder实例
     */
    public static <T> InstanceBuilder<T> of(Class<T> instClass){
        return new InstanceBuilder<>(instClass);
    }

    /**
     * 设置实例属性值
     * 使用函数式接口方式设置实例的特定属性,支持链式调用
     *
     * @param <V> 属性值类型
     * @param fnSet 设置属性的函数式接口
     * @param v 要设置的属性值
     * @return 当前构建器实例(支持链式调用)
     */
    public <V> InstanceBuilder<T> set(BuildFunction<T, V> fnSet, V v){
        fnSet.call(inst, v);
        return this;
    }

    /**
     * 带校验的set方法(重载,想用时用,不想用还能用原来的)
     * @param fnSet 设置属性的函数式接口
     * @param v 要设置的属性值
     * @param validator 校验器
     * @return 当前构建器实例(支持链式调用)
     * @param <V> 属性值类型
     */
    public <V> InstanceBuilder<T> set(BuildFunction<T, V> fnSet, V v, Predicate<V> validator){
        // 先校验:符合条件才设置属性,不符合就报错
        if (!validator.test(v)) {
            throw new IllegalArgumentException("属性值不对:" + v);
        }
        fnSet.call(inst, v); // 校验通过再调用你原有的设置逻辑
        return this;
    }

    /**
     * 构建并返回配置完成的实例
     *
     * @return 构建完成的实例对象
     */
    public T build(){
        return inst;
    }
}

使用场景

创新对象类
java 复制代码
public class User {
    private String name;
    private Integer age;
    private String email;
    // 无参构造
    public User() {}
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}
场景 1:创建新实例(无参构造)

通过 InstanceBuilder.of(Class) 创建新实例,并链式设置属性:

java 复制代码
// 构建 User 实例:无校验
User user = InstanceBuilder.of(User.class)
    .set(User::setName, "张三")
    .set(User::setAge, 18)
    .set(User::setEmail, "zhangsan@163.com")
    .build();
System.out.println(user.getName()); 
场景 2:修改对象实例

通过 InstanceBuilder.of(实例) 修改已有对象的属性,适用于 DTO 转换、对象更新等场景:

java 复制代码
User user = InstanceBuilder.of(User.class)
    .set(User::setName, "张三") // Lambda替代setter调用
    .set(User::setAge, 25)
    .set(User::setEmail, "zhangsan@xxx.com")
    .build();
System.out.println(user.getName()); // 输出:张三

user.setName("李四");
// 修改现有实例的属性
User updatedUser = InstanceBuilder.of(user)
    .set(User::setAge, 30)
    .set(User::setEmail, "lisi@163.com")
    .build();
System.out.println(updatedUser.getAge()); // 输出:30
System.out.println(updatedUser.getName()); // 输出:李四
场景 3:带属性校验的构建

通过 set(BuildFunction, value, Predicate) 添加校验逻辑,例如校验年龄是否大于 0、邮箱是否非空等:

java 复制代码
try {
    User validUser = InstanceBuilder.of(User.class)
        .set(User::setName, "王五", name -> name.length() >= 2) 
        .set(User::setAge, -5, age -> age > 0)
        .set(User::setEmail, "wangwu@163.com", email -> email.contains("@")) 
        .build();
} catch (IllegalArgumentException e) {
    System.out.println(e.getMessage());
}

基于 JDK8 的 Lambda 特性,我们精心设计了一套简洁高效的对象构建方案。该方案通过 SetterFunction 函数式接口封装 setter 逻辑,并配合 InstanceBuilder 实现对象构建流程,既简化了传统 setter 方法的冗长调用,又避免了手动编写 Builder 模式的重复工作。

这套构建工具具备以下显著优势:

  1. 代码简洁但功能强大,能够满足复杂对象构建的需求。
  2. 对业务代码零侵入,不会对现有业务逻辑产生任何干扰。
  3. 使用灵活且无需额外依赖,可无缝集成到现有项目中。
  4. 兼容所有 JDK8+ 项目环境,具有广泛的适用性。

特别适用于需要频繁构建对象、属性较多或需要进行参数校验的场景,能够大幅提升开发效率,同时保证代码的可读性和可维护性。


相关推荐
xiaowu0802 小时前
C# GetType的常规用法汇总
开发语言·c#
飞火流星020272 小时前
【Arthas工具】使用Trace命令分析Java JVM方法调用链路及耗时
java·jvm·arthas·jvm性能调优·java方法调用链路分析及耗时·jvm实时分析·jvm方法调用实时分析
Trouvaille ~2 小时前
【Linux】文件描述符与重定向原理:揭开Linux文件操作的神秘面纱
linux·运维·服务器·开发语言·内核·进程·重定向
熬了夜的程序员2 小时前
【Rust学习之路】第 0 章:理解 Rust 的核心哲学
开发语言·学习·rust
MoonBit月兔2 小时前
海外开发者实践分享:用 MoonBit 开发 SQLC 插件(其二)
开发语言·javascript·数据库·redis·mysql·moonbit
scan7242 小时前
python mcp see
开发语言·数据库·python
monkey_slh2 小时前
JS逆向实战——最新某东cfe滑块
开发语言·前端·javascript
Han.miracle2 小时前
Spring MVC 请求参数处理全解析
java·请求
winfield8212 小时前
Java 的静态代理和动态代理
java·代理模式