使用场景:

  1. 相同的方法,不同的执行顺序,产生不同的事件结果时
  2. 多个部件或零件,都可以装配到一个对象中,但是产生的结果都不相同时
  3. 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的作用
  4. 当初始化一个类特别复杂,比如参数多,很多参数有默认值时

优点

  • 良好的封装性,使得客户端不需要知道产品内部实现的细节
  • 建造者独立,扩展性强

缺点:

  • 产生多余的Builder对象、Director对象,消耗内存

栗子

public class User {
    private final String name;        //必选,final修饰,属性不可修改
    private final String cardID;      //必选
    private final int age;            //可选
    private final String address;      //可选
    private final String phone;        //可选

    private User(UserBuilder userBuilder){      //user类的构造函数为私有的
        this.name=userBuilder.name;
        this.cardID=userBuilder.cardID;
        this.age=userBuilder.age;
        this.address=userBuilder.address;
        this.phone=userBuilder.phone;
    }

    public String getName() {
        return name;
    }

    public String getCardID() {
        return cardID;
    }

    public int getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }

    public String getPhone() {
        return phone;
    }

    public static class UserBuilder{
        private final String name;    //必选对象用final修饰
        private final String cardID;
        private int age;
        private String address;
        private String phone;

        public UserBuilder(String name,String cardID){ //构造方法只接受必传的参数
            this.name=name;
            this.cardID=cardID;
        }

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

        public UserBuilder address(String address){
            this.address=address;
            return this;
        }

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

        public User build(){
            return new User(this);
        }
    }
}

调用方法

new User.UserBuilder("Jack","10086")
                .age(25)
                .address("GuangZhou")
                .phone("13800138000")
                .build();

关于线程安全

  • Builder模式是非线程安全的,如果要在Builder内部类中检查一个参数的合法性,必需要在对象创建完成之后再检查

正确示例:

public User build() {
  User user = new user(this);
  if (user.getAge() > 120) {
    throw new IllegalStateException(Age out of range); // 线程安全
  }
  return user;
}