01_手把手实现 Builder 模式创建对象

01_手把手实现 Builder 模式创建对象

这是一个常见的 Builder 模式创建对象的示例:

Person person = Person.builder()  // 静态入口
        .firstName("John")        // 链式调用
        .lastName("Doe")
        .age(30)
        .build();                 // 最终构造
为什么需要 Builder 模式?

当类的字段较多(尤其是可选参数)、构造逻辑复杂,或字段为 final 类型(不可通过 setter 修改)时,直接通过构造方法或 new + setter 的方式会变得笨拙。

Builder 模式能:

  1. 支持链式调用,提升代码可读性;
  2. 分离对象构建与表示,灵活处理参数组合;
  3. 保证对象不可变性,避免中途状态不一致;
  4. 解决构造方法参数爆炸问题(例如避免 new Person(a, b, c, d...))。

实现步骤详解

假设我们现在有一个场景,需要定义一个 Person 类,并且可以通过 Builder 模式来创建对象。

下面,我们来一步一步实现。

1. 首先,我们需要定义一个 Person 类与对应字段。
public class Person {
    private final String firstName; 
    private final String lastName;
    private final int age;

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    
    public Person() {}
    
}

上面,我们定义了一个 Person 类与我们最常见的全参和无参构造方法,我们现在可以创建一个 Person 类型对象,但是我们仍然无法实现链式编程。

2. 创建内部静态类 Builder 及静态方法 builder()
public class Person {
    private final String firstName; 
    private final String lastName;
    private final int age;

    public static class Builder {
        
    }

    // 入口方法:获取 Builder 实例
    public static Builder builder() {
        return new Builder();
    }
}

上面,我们移除了全参和无参构造方法,我们创建了一个静态内部类 Builder 和 静态方法 builder(),方法返回值为一个 Builder 类型对象。

注意:定义静态方法的原因是我们可以通过 类.方法 的方式去调用一个方法。

现在我们可以通过 Person.builder() 来获取到一个 Builder 类型对象,例如:

Person person = Person.builder();

虽然有内个意思了,但是 person 的属性现在仍然是为空的。

3. 丰富静态内部类 Builder
public class Person {
    private final String firstName; 
    private final String lastName;
    private final int age;

    public static class Builder {
        private String firstName;  
        private String lastName;
        private int age;
    }

    public static Builder builder() {
        return new Builder();
    }
}

我们为静态内部类 Builder 添加了与 Person 类的同名字段 firstNamelastNameage。现在我们还是和第二步一样,只能构建出空的 Person 类型的 person 变量,无法为其赋值。

4.为静态内部类 Builder 添加方法
public class Person {
    private final String firstName; 
    private final String lastName;
    private final int age;

    public static class Builder {
        private String firstName;  
        private String lastName;
        private int age;

        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }

    }

    public static Builder builder() {
        return new Builder();
    }
}

我们为静态内部类 Builder 添加了与属性同名的方法 firstName()lastName()age(),我们现在可以通过这三个方法为静态内部类 Builder 的属性进行赋值,并且方法返回值为 Builder 类型对象。

示例:

Person person = Person.builder()  
        .firstName("John")       
        .lastName("Doe")
        .age(30);

解析:我们在调用 Person.builder() 时,会创建一个 Builder 类型对象,由于该类为静态内部类,所以可以直接通过 类.方法 的方式访问方法,那在调用 firstName("John") 方法时,会为 BuilderfirstName 属性进行赋值并返回一个 Builder 类型对象,因此我们可以继续调用其他方法来进行赋值。

现在可以为 Builder 类型对象赋值,虽然起到了形似的效果,但是还是不能为 person 变量赋值。

5.完善静态内部类 Builder
public class Person {
    private final String firstName; 
    private final String lastName;
    private final int age;

    public static class Builder {
        private String firstName;  
        private String lastName;
        private int age;

        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public Builder age(int age) {
            this.age = age;
            return this;
        }
        
        public Person build() {
            return new Person(firstName, lastName, age);
        }

    }

    public static Builder builder() {
        return new Builder();
    }
}

我们添加了一个 build() 方法,该方法会创建一个 Person 类型对象并为其赋值,值即 Builder 中的属性值。

此时我们便可以实现创建一个 Person 类型对象,并为其赋值了。

6. 使用 Builder 创建对象
Person person = Person.builder()  // 静态入口
        .firstName("John")        // 链式调用
        .lastName("Doe")
        .age(30)
        .build();                 // 最终构造

上面的流程是,我们声明了一个 Person 类型的 person 变量,然后通过 类.方法 的方式调用了静态方法 builder(),即 Person.builder(),该方法会返回一个 Builder 类型的对象,然后继续调用 firstName("John") 为 Builder 类的属性 firstName 赋值为 "John",并返回一个 Builder 类型对象,以此类推,最终我们调用 build() 创建一个 Person 类型对象,并将其赋值为 Builder 类的属性的值,并返回。最终 person 变量接收到这个 Person 类型的对象。


对比普通 new + setter 方式
特性 Builder 模式 new + setter
不可变对象 ✅ 字段为 final ❌ 需手动保证
线程安全 ✅ 对象创建后不可变 ❌ 中途状态可能被修改
参数校验 ✅ 可在 build() 统一校验 ❌ 分散在多个 setter
多参数构造 ✅ 无需记忆顺序 ❌ 构造方法易混淆
代码可读性 ✅ 链式调用清晰明了 ❌ 冗长的 setter 调用

高级技巧:参数校验与默认值
1. 添加参数校验

build() 方法中确保参数有效:

public Person build() {
    if (firstName == null || lastName == null) {
        throw new IllegalArgumentException("姓名不能为空!");
    }
    return new Person(firstName, lastName, age);
}
2. 支持默认值
public static class Builder {
    private String firstName = "Anonymous"; // 默认值
    // ... 其他字段 ...
}

总结

通过手动实现 Builder 模式,我们能够:

  1. 优雅处理多参数、可选参数场景;
  2. 保证对象不可变性,提升线程安全性;
  3. 集中校验逻辑,避免无效状态;
  4. 提供流畅的 API 提升代码可读性。

实现 Builder 模式是更可靠的选择。

你可能感兴趣的:(【后端开发】Java,碎碎念,java,开发语言,设计模式,建造者模式)