您的位置:首页 > Web前端

Effective Java 学习笔记(2)

2010-01-24 19:12 375 查看
有时,我们在写一个构造函数时,经常因为它包含众多的参数而苦恼,这时可以考虑用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模式比前面现两种模式更加复杂,如果不是有太多的参数的话,就没有必要使用这种模式。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mutsinghua/archive/2010/01/15/5193709.aspx
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: