第五节:建造者模式——变种

一、分析需求

  当需要创建一个多属性的对象,例如:创建一个不可变的 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 的 方法创建的对象可能还没有设置完全。

原文地址:https://www.cnblogs.com/niujifei/p/14256691.html