一、前置总结

在创建类时,若需要初始化多个参数,重叠构造器模式可行,但仍不利于客户端编写,且难以阅读;JavaBeans模式可行,但是会使得类可能处于不一致状态。而构建器Builder能够较好的处理多参数情况。

二、细节

如果用盖房子比作创建类,属性相当于房子中家具的品牌。

1. 重叠构造器模式(一味堆叠家具的房子,很容易乱。捏码,谁买的苹果牌抽油烟机?)

多参数情况,在业务中用于封装业务数据的类中很常见。如果利用构造器创建类,如下:

public class Person {
    private final String name;         // 必填字段
    private final int age;             // 必填字段
    private final String phone;        // 可选字段
    private final String address;      // 可选字段

    // 基础构造器(仅必填字段)
    public Person(String name, int age) {
        this(name, age, null);
    }

    // 扩展构造器(增加phone字段)
    public Person(String name, int age, String phone) {
        this(name, age, phone, null);
    }

    // 全参构造器(所有字段)
    public Person(String name, int age, String phone, String address) {
        this.name = name;
        this.age = age;
        this.phone = phone;
        this.address = address;
    }

    // Getter方法
    public String getName() { return name; }
    public int getAge() { return age; }
    public String getPhone() { return phone; }
    public String getAddress() { return address; }
}
 
// 仅初始化必填字段
Person p1 = new Person("Alice", 25);

// 初始化必填字段+phone
Person p2 = new Person("Bob", 30, "13800138000");

// 初始化全部字段
Person p3 = new Person("Charlie", 35, "13900139000", "Beijing");
 

这要求程序员在编写代码时知道参数顺序,这使得参数量越多,编码成本越大。加入上述Person类在创建时,“phone”和“address”两个参数的输入颠倒,编译器也不会出错,但是闹笑话了。

2. JavaBeans模式(先规划房子的空间,然后放家具,容易出现家具还未买好,人已入住的情况。虚假广告,退钱。)

public class User implements Serializable {
    // 必需:无参构造器
    public User() {}

    // 私有字段(属性)
    private String name;
    private int age;
    private boolean active;

    // Getter 和 Setter 方法(标准命名规范)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    // Boolean 类型属性的特殊命名
    public boolean isActive() {
        return active;
    }

    public void setActive(boolean active) {
        this.active = active;
    }
}
 

JavaBeans模式最大缺点在于使得类可能处于不一致状态。

User user = new User();

user.setName("xxx");

user.getAge();

在还未初始化属性age的情况下,直接调用,然后报错。这是由于JavaBeans:

  1. 无参构造函数无法校验必要属性无参构造函数不接收任何参数,因此无法在对象创建时强制要求初始化必要属性。它只能将属性设置为默认值,而无法保证 “对象创建即有效”。

  2. setter 方法是 “可选操作”setter方法的调用完全依赖开发者的自觉性:

    • 开发者可能忘记调用某个必要属性的setter(如漏设password);
    • 可能在设置完部分属性后,就将对象传递给其他方法使用(如提前存入数据库、传入校验逻辑)。
  3. 对象创建与初始化分离JavaBeans 的设计将 “对象创建” 和 “属性初始化” 拆分为两个独立步骤,而没有机制保证 “初始化完成前对象不可用”。这与 “构造函数一次性初始化所有必要属性” 的模式(如带参构造)形成鲜明对比。

3. Builder(建造者)模式(委托一个装潢师傅买家具,师傅会提醒你哪些家具必须你定好牌子,哪些你不说,师傅就买默认的牌子,一手打造可以拎包入住的房子。五星好评!!!)

public class User {
    // 必需属性
    private final String username;
    // 可选属性
    private final String email;
    private final int age;
    private final String phone;

    // 私有构造器(仅Builder可访问)
    private User(Builder builder) {
        this.username = builder.username;
        this.email = builder.email;
        this.age = builder.age;
        this.phone = builder.phone;
    }

    // Builder静态内部类
    public static class Builder {
        private final String username;  // 必需属性
        private String email = "";
        private int age = 0;
        private String phone = "";

        // 必需参数构造器
        public Builder(String username) {
            this.username = username;
        }

        // 可选参数设置方法(返回Builder实现链式调用)
        public Builder email(String email) {
            this.email = email;
            return this;
        }

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

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

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

    // 示例用法
    public static void main(String[] args) {
        User user = new User.Builder("john_doe")
                .email("john@example.com")
                .age(30)
                .phone("123-456-7890")
                .build();
    }
}
 

等到后续相关条目看完补充。

三、总结

Builder模式在创建类时,需要创建构建器,有性能开销;且代码也比较冗长。《EJ》推荐一般在有4个以上时用它,毕竟谁会为了几个家具请师傅呢?

如果将来有添加参数的可能,一开始就使用构建器更好。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐