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


    一、分析需求

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

  • 相关阅读:
    API之绘图函数
    DotNetCharting
    Rule engine
    股票
    PHP
    获取Excel.dll
    Excel develop
    几个不错的开源的.net界面控件[转贴]
    关于EXCEL文件双击打不开的问题
    Regular expression
  • 原文地址:https://www.cnblogs.com/niujifei/p/14256691.html
Copyright © 2020-2023  润新知