1.适用场景

当遇到多个构造器参数时,要考虑使用构建器(Builder模式)

2. Builder模式的使用场景

2.1 使用Java Bean的setter方法来设置对象属性

  1. public class Person {
  2. //必要参数
  3. private int id;
  4. private String name;
  5. //可选参数
  6. private int age;
  7. private String sex;
  8. private String phone;
  9. private String address;
  10. private String desc;
  11. // set/get方法忽略
  12. }
  13. //在使用该Person类的时候,会写出如下的代码:
  14. Person person = new Person();
  15. person.setId(1);
  16. person.setName("张三");
  17. person.setAge(22);
  18. person.setSex("男");
  19. person.setPhone("9999999999");
  20. person.setAddress("beijing");
  21. person.setDesc("JavaBeans模式");

优点

易于阅读,并且可以只对有用的成员变量赋值

缺点

1.成员变量不可以是 final 类型,失去了不可变对象的很多好处
2.对象状态不连续。你必须调用7次setter方法才能得到一个具备7个属性值得变量,在这期间用户可能拿到不完整状态的对象。如果有N个属性,岂不是要person.setXXX调用N次?此种方式不优雅

什么是对象状态不连续?

解释一下:这种方式是先创建对象、后赋值,用户不知道什么时候拿到的对象是完整的,构建完成的。很有可能你只setter了一两个属性就返回了,一些必要的属性没有被赋值。

2.2使用重叠构造器

在这种模式下,需要提供一个只有必要参数的构造器,第二个构造器有一个可选参数,第三个有两个可选参数,依此类推,最后一个构造器包含所有的可选参数。

  1. public class Person {
  2. //必要参数
  3. private final int id;
  4. private final String name;
  5. //可选参数
  6. private int age;
  7. private String sex;
  8. private String phone;
  9. private String address;
  10. private String desc;
  11. public Person(int id, String name) {
  12. this(id, name, 0);
  13. }
  14. public Person(int id, String name, int age) {
  15. this(id, name, age, "");
  16. }
  17. public Person(int id, String name, int age, String sex) {
  18. this(id, name, age, sex, "");
  19. }
  20. public Person(int id, String name, int age, String sex, String phone) {
  21. this(id, name, age, sex, phone, "");
  22. }
  23. public Person(int id, String name, int age, String sex, String phone,
  24. String address) {
  25. this(id, name, age, sex, phone, address, "");
  26. }
  27. public Person(int id, String name, int age, String sex, String phone,
  28. String address, String desc) {
  29. this.id = id;
  30. this.name = name;
  31. this.age = age;
  32. this.sex = sex;
  33. this.phone = phone;
  34. this.address = address;
  35. this.desc = desc;
  36. }
  37. }

优点

简单

缺点

这个构造器调用,通常需要许多你本不想设置的参数,但还是不得不为它们传递值。但使用者在使用时,可得仔细了解你每个构造函数,否则一不小心填错顺序也不知道。而且如果有十几个属性,就歇菜了……(我也没见过有十几个参数的构造函数)

所以只适用于成员变量少的情况,太多了不容易理解、维护。

简而言之:重叠构造器可行,但是当有许多参数的时候,创建使用代码会很难写,并且较难以阅读。

2.3变种Builder模式

  1. public class Person {
  2. //必要参数
  3. private final int id;
  4. private final String name;
  5. //可选参数
  6. private int age;
  7. private String sex;
  8. private String phone;
  9. private String address;
  10. private String desc;
  11. private Person(Builder builder) {
  12. this.id = builder.id;
  13. this.name = builder.name;
  14. this.age = builder.age;
  15. this.sex = builder.sex;
  16. this.phone = builder.phone;
  17. this.address = builder.address;
  18. this.desc = builder.desc;
  19. }
  20. public static class Builder {
  21. //必要参数
  22. private final int id;
  23. private final String name;
  24. //可选参数
  25. private int age;
  26. private String sex;
  27. private String phone;
  28. private String address;
  29. private String desc;
  30. public Builder(int id, String name) {
  31. this.id = id;
  32. this.name = name;
  33. }
  34. public Builder age(int val) {
  35. this.age = val;
  36. return this;
  37. }
  38. public Builder sex(String val) {
  39. this.sex = val;
  40. return this;
  41. }
  42. public Builder phone(String val) {
  43. this.phone = val;
  44. return this;
  45. }
  46. public Builder address(String val) {
  47. this.address = val;
  48. return this;
  49. }
  50. public Builder desc(String val) {
  51. this.desc = val;
  52. return this;
  53. }
  54. public Person build() {
  55. return new Person(this);
  56. }
  57. }
  58. }

观察上述代码,可以看到变种Builder模式包括以下内容:

(1)在要构建类的内部,创建一个静态内部类Builder;

(2)静态内部类的属性要与构建类的属性一致;

(3)构建类的构造参数是静态内部类,使用静态内部类的变量为构建类逐一赋值;

(4)静态内部类提供参数的setter方法,并且返回值是当前Builder对象;

(5)最终提供一个build方法new出来一个构建类的对象,参数是当前Builder对象;

  1. public class Test {
  2. public static void main(String[] args) {
  3. Person person = new Person.Builder(1, "张小毛")
  4. .age(22).sex("男").desc("使用builder模式").build();
  5. System.out.println(person.toString());
  6. }
  7. }

优点

看起来很整齐;先赋值,后创建对象,最终调用build()方法才创建了构建类的对象,保证了状态的完整性。

缺点

需要额外写的代码多了点。

小结:

变种Builer模式相比于重叠构造器模式和JavaBean模式,Builder模式实现的对象更利于使用。

对Builer模式使用方法的总结:

1.外部类的构造函数私有,且参数为静态内部类
2.静态内部类拥有外部类相同的属性
3.为每一个属性,写一个方法,返回的是当前Builder对象
4.最后一个方法是build方法,用于构建一个外部类