Effective Java 学习笔记(2)

来源:互联网 发布:linux 挂载移动硬盘 编辑:程序博客网 时间:2024/06/08 00:52

 有时,我们在写一个构造函数时,经常因为它包含众多的参数而苦恼,这时可以考虑用Builder模式来创建对象

 

如,我们要设计一个营养成份的类,包含能量,蛋白质,脂肪,钙,铁,锌,维生素A, 维生素B1 ... 等,但在构造的时候,不一定每次都需要这些参数,如钙,铁,锌和维生素等是可选的,为了适应多种可能的搭配,比较原始的办法就是采用telescoping constructor模式,例子如下。

 

public class Nutrition

{

          private int calories;

          private int protein;

          private int fat;

          private int ca;

          private int fe;

          private int Va;

          private int Vb;

          ...

 

          public Nutrition(int cal, int pro){...}

          public Nutrition(int cal, int pro, int fat){...}

          public Nutrition(int cal, int pro, int fat, int ca){...}

          public Nutrition(int cal, int pro, int fat, int ca, int fe){...}

          public Nutrition(int cal, int pro, int fat, int ca, int fe, int ){...}

          public Nutrition(int cal, int pro, int fat, int ca, int fe, int Va){...}

           .......

}

 

这种方法的缺点很明显,一个函数的参数一旦超过3个,用户就很容易把顺序搞混,而更杯具的是这种情况编译器无法识别,非常不易查错。

 

第二种方法是JavaBean模式。

 

         

public class Nutrition

{

          private int calories;

          private int protein;

          private int fat;

          private int ca;

          private int fe;

          private int Va;

          private int Vb;

          ...

 

          public Nutrition(){...}

         

          public setCal(int cal);

          public setPro(int pro);

          public setfat(int fat);

          public setca(int ca);

          public setfe(int fe);

          .......

}

 

这种方式的缺点是在整个构造对象的过程中,其状态不是一致的(inconsistent state),即在创建好一个对象后,这个对象的状态在后面的某个时候内仍然是在变化的(因为其值发生了改变),此外,这种方法只能构造一个可变(mutable)对象,必须采用附加的方法保证线程安全。

 

 所以,书中推荐了第三种方法利用Builder来构造。

public class Nutrition

{

          private final int calories;

          private final  int protein;

          private final int fat;

          private final int ca;

          private final int fe;

          private final int Va;

          private final int Vb;

 

          public static class Builder {

                private final int calories;  //必有参数

                private final int protein;  //必有参数

    

                private final int fat;    //可选参数

                private final int ca;    //可选参数

                private final int fe;    //可选参数

                private final int Va;   //可选参数

                private final int Vb;   //可选参数

              

                public Builder(int cal,int pro) {...};

               

                public Builder fat(int fat){...};

                public Builder ca(int ca){...};

                public Builder fe(int fe){...};

              

                public Nutrition builder(Builder builder)

                {

                       return new Nutrition(this);

                 }

          }  //end of Builder

         

          private Nutrition(Builder builder)

          {

                     calories = builder.calories;

                     protein = builder.protein;

                     ca = builder.ca;

                     fe = builder.fe;

                    ....

           }

}

 

使用时可以采用以下代码:

        Nutrition nu = new Nutrition.Builder(1,2).fat(45).ca(456).fe(4).builder();

 

其中,Builder()中的是必选参数,其他的是可选参数。

 

采用这种方式,代码易读易写,参数初始化的顺序也无关紧要。

 

当然,它也有缺点。它必须先构造一个Builder对象,其开销在性能问题很关键的场合的是不适用的。另外,相比之下,Builder模式比前面现两种模式更加复杂,如果不是有太多的参数的话,就没有必要使用这种模式。

 

 

原创粉丝点击