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
如,我们要设计一个营养成份的类,包含能量,蛋白质,脂肪,钙,铁,锌,维生素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
相关文章推荐
- 我的Effective Java 学习笔记(一)
- Effective Java 学习笔记(1)
- Effective Java 学习笔记(2)
- effective java 学习笔记(一) 2012-4-24
- effective java 学习笔记
- effective-java 学习笔记(1)
- Effective Java学习笔记 第61条: 抛出与抽象相对应的异常
- Effective Java 学习笔记 (10)
- Effective Java 学习笔记(15)
- Effective Java 学习笔记(二)
- Effective Java 学习笔记(8)
- Effective Java 学习笔记 (6)
- effective java 学习笔记(一)
- Effective Java-学习笔记(10-11章)
- effective java 学习笔记(二)
- effective Java 学习笔记(三)
- Effective Java-学习笔记(2-5章)
- Effective Java 学习笔记(四、五)
- Effective Java学习笔记: 第58条 对可恢复的情况使用受检异常,对于编程错误使用运行时异常
- effective java 学习笔记——全书纲要