一、分析需求
当需要创建一个多属性的对象,例如:创建一个不可变的 Person 对象,这个 Person 拥有多个属性,但其中名字和性别是必须有的。
代码实现:
1 public class Person {
2 /*名字(必须)*/
3 private final String name;
4 /*性别(必须)*/
5 private final String gender;
6 /*年龄(非必须)*/
7 private final String age;
8 /*鞋子(非必须)*/
9 private final String shoes;
10 /*衣服(非必须)*/
11 private final String clothes;
12 /*钱(非必须)*/
13 private final String money;
14 /*房子(非必须)*/
15 private final String house;
16 /*汽车(非必须)*/
17 private final String car;
18 /*职业(非必须)*/
19 private final String career;
20
21 public Person(String name,String gender,String age,String shoes,String clothes,String money,String house,String car,String career){
22 this.name = name;
23 this.gender = gender;
24 this.age = age;
25 this.shoes = shoes;
26 this.clothes = clothes;
27 this.money = money;
28 this.house = house;
29 this.car = car;
30 this.career = career;
31 }
32
33 public Person(String name, String gender){
34 this(name,gender,null,null,null,null,null,null,null);
35 }
36
37 }
分析:多个需要传入非必须属性的时候,这个构造方法调用起来不是很方便,因为这个构造方法参数太多了,很容易传错。
二、优化一
代码实现:
1 public class Person {
2 /*名字(必须)*/
3 private String name;
4 /*性别(必须)*/
5 private String gender;
6 /*年龄(非必须)*/
7 private String age;
8 /*鞋子(非必须)*/
9 private String shoes;
10 /*衣服(非必须)*/
11 private String clothes;
12 /*钱(非必须)*/
13 private String money;
14 /*房子(非必须)*/
15 private String house;
16 /*汽车(非必须)*/
17 private String car;
18 /*职业(非必须)*/
19 private String career;
20
21 public String getName() {
22 return name;
23 }
24
25 public void setName(String name) {
26 this.name = name;
27 }
28
29 public String getGender() {
30 return gender;
31 }
32
33 public void setGender(String gender) {
34 this.gender = gender;
35 }
36
37 public String getAge() {
38 return age;
39 }
40
41 public void setAge(String age) {
42 this.age = age;
43 }
44
45 public String getShoes() {
46 return shoes;
47 }
48
49 public void setShoes(String shoes) {
50 this.shoes = shoes;
51 }
52
53 ......
54
55 }
分析:这样一来,只要创建一个对象,想要赋什么值 set 就可以了,但是这样使用 set 方法,违背了刚开始这个对象不可变的需求,其次用 set 方法一次次赋值,比较繁琐;另外这种方式很可能让你得到一个不完整的对象,可能会忘记把部分信息 set 进去。
三、优化二
代码实现:
1 public class Person {
2 /*名字(必须)*/
3 private final String name;
4 /*性别(必须)*/
5 private final String gender;
6 /*年龄(非必须)*/
7 private final String age;
8 /*鞋子(非必须)*/
9 private final String shoes;
10 /*衣服(非必须)*/
11 private final String clothes;
12 /*钱(非必须)*/
13 private final String money;
14 /*房子(非必须)*/
15 private final String house;
16 /*汽车(非必须)*/
17 private final String car;
18 /*职业(非必须)*/
19 private final String career;
20
21
22 private Person(Builder builder) {
23 this.name = builder.name;
24 this.gender = builder.gender;
25 this.age = builder.age;
26 this.shoes = builder.shoes;
27 this.clothes = builder.clothes;
28 this.money = builder.money;
29 this.house = builder.house;
30 this.car = builder.car;
31 this.career = builder.career;
32 }
33
34 public static class Builder {
35 private final String name;
36 private final String gender;
37 private String age;
38 private String shoes;
39 private String clothes;
40 private String money;
41 private String house;
42 private String car;
43 private String career;
44
45 public Builder(String name,String gender) {
46 this.name = name;
47 this.gender = gender;
48 }
49
50 public Builder age(String age) {
51 this.age = age;
52 return this;
53 }
54
55 public Builder car(String car) {
56 this.car = car;
57 return this;
58 }
59
60 public Builder shoes(String shoes) {
61 this.shoes = shoes;
62 return this;
63 }
64
65 public Builder clothes(String clothes) {
66 this.clothes = clothes;
67 return this;
68 }
69
70 public Builder money(String money) {
71 this.money = money;
72 return this;
73 }
74
75 public Builder house(String house) {
76 this.house = house;
77 return this;
78 }
79
80 public Builder career(String career) {
81 this.career = career;
82 return this;
83 }
84
85 public Person build(){
86 return new Person(this);
87 }
88 }
测试代码:
1 /**
2 * 非必须的属性可以根据需要任意设置,非常灵活,而且这样先设置属性再创建对象,
3 * 最终获取的对象一定是你预期的完整对象,不会像用之前set的方法创建的对象可能还没有设置完全。
4 */
5 public class Client {
6 public static void main(String[] args) {
7 PersonTest person = new PersonTest.Builder("张三","男")
8 .age("12")
9 .money("1000000")
10 .car("宝马")
11 .build();
12 System.out.println(person);
13 }
14 }
分析:可以根据需求是否给属性添加 final 修饰。
(1)在 Person 类中定义一个内部类 Builder,这个 Builder 内部类的属性要和 Person 中的相同,并且必须有的属性要用 final 修饰,防止这些属性没有被复制,其他非必须的属性不能用 final,因为如果加了 final,就必须进行初始化,这样这些非必须的属性又变成必须的。
(2)在内部类中定义一个构造方法,传入必须有的属性。
(3)其他非必须的属性都通过方法设置,每个方法都返回 Builder 对象自身,方便链式调用;
(4)最后一定一个 build() 方法,将 Builder 对象传入 Person 的私有方法,最终返回一个对象。
(5)这样设置非必须的属性可以根据需要任意设置,非常灵活,而且这样先设置属性再创建对象,最终获取的对象一定是你预期的完整对象,不会像用之前 set 的 方法创建的对象可能还没有设置完全。