1.适用场景
当遇到多个构造器参数时,要考虑使用构建器(Builder模式)
2. Builder模式的使用场景
2.1 使用Java Bean的setter方法来设置对象属性
public class Person {//必要参数private int id;private String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;// set/get方法忽略}//在使用该Person类的时候,会写出如下的代码:Person person = new Person();person.setId(1);person.setName("张三");person.setAge(22);person.setSex("男");person.setPhone("9999999999");person.setAddress("beijing");person.setDesc("JavaBeans模式");
优点
易于阅读,并且可以只对有用的成员变量赋值
缺点
1.成员变量不可以是 final 类型,失去了不可变对象的很多好处
2.对象状态不连续。你必须调用7次setter方法才能得到一个具备7个属性值得变量,在这期间用户可能拿到不完整状态的对象。如果有N个属性,岂不是要person.setXXX调用N次?此种方式不优雅
什么是对象状态不连续?
解释一下:这种方式是先创建对象、后赋值,用户不知道什么时候拿到的对象是完整的,构建完成的。很有可能你只setter了一两个属性就返回了,一些必要的属性没有被赋值。
2.2使用重叠构造器
在这种模式下,需要提供一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,依此类推,最后一个构造器包含所有的可选参数。
public class Person {//必要参数private final int id;private final String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;public Person(int id, String name) {this(id, name, 0);}public Person(int id, String name, int age) {this(id, name, age, "");}public Person(int id, String name, int age, String sex) {this(id, name, age, sex, "");}public Person(int id, String name, int age, String sex, String phone) {this(id, name, age, sex, phone, "");}public Person(int id, String name, int age, String sex, String phone,String address) {this(id, name, age, sex, phone, address, "");}public Person(int id, String name, int age, String sex, String phone,String address, String desc) {this.id = id;this.name = name;this.age = age;this.sex = sex;this.phone = phone;this.address = address;this.desc = desc;}}
优点
简单
缺点
这个构造器调用,通常需要许多你本不想设置的参数,但还是不得不为它们传递值。但使用者在使用时,可得仔细了解你每个构造函数,否则一不小心填错顺序也不知道。而且如果有十几个属性,就歇菜了……(我也没见过有十几个参数的构造函数)
所以只适用于成员变量少的情况,太多了不容易理解、维护。
简而言之:重叠构造器可行,但是当有许多参数的时候,创建使用代码会很难写,并且较难以阅读。
2.3变种Builder模式
public class Person {//必要参数private final int id;private final String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;private Person(Builder builder) {this.id = builder.id;this.name = builder.name;this.age = builder.age;this.sex = builder.sex;this.phone = builder.phone;this.address = builder.address;this.desc = builder.desc;}public static class Builder {//必要参数private final int id;private final String name;//可选参数private int age;private String sex;private String phone;private String address;private String desc;public Builder(int id, String name) {this.id = id;this.name = name;}public Builder age(int val) {this.age = val;return this;}public Builder sex(String val) {this.sex = val;return this;}public Builder phone(String val) {this.phone = val;return this;}public Builder address(String val) {this.address = val;return this;}public Builder desc(String val) {this.desc = val;return this;}public Person build() {return new Person(this);}}}
观察上述代码,可以看到变种Builder模式包括以下内容:
(1)在要构建类的内部,创建一个静态内部类Builder;
(2)静态内部类的属性要与构建类的属性一致;
(3)构建类的构造参数是静态内部类,使用静态内部类的变量为构建类逐一赋值;
(4)静态内部类提供参数的setter方法,并且返回值是当前Builder对象;
(5)最终提供一个build方法new出来一个构建类的对象,参数是当前Builder对象;
public class Test {public static void main(String[] args) {Person person = new Person.Builder(1, "张小毛").age(22).sex("男").desc("使用builder模式").build();System.out.println(person.toString());}}
优点
看起来很整齐;先赋值,后创建对象,最终调用build()方法才创建了构建类的对象,保证了状态的完整性。
缺点
需要额外写的代码多了点。
小结:
变种Builer模式相比于重叠构造器模式和JavaBean模式,Builder模式实现的对象更利于使用。
对Builer模式使用方法的总结:
1.外部类的构造函数私有,且参数为静态内部类;
2.静态内部类拥有外部类相同的属性;
3.为每一个属性,写一个方法,返回的是当前Builder对象;
4.最后一个方法是build方法,用于构建一个外部类;
