第一条:考虑用静态工厂方法代替构造器
静态工厂方法:只是一个返回类实例的静态方法。
例:
public static Boolean valueOf(boolean b){
return b ? Boolean.TRUE : Boolean.FALSE;
}
提供静态工厂方法而不是公有的构造器的优势:
1.静态工厂方法与构造器不同的第一大优势在于,它们有名称。(避免了多个构造器带来的参数过多,不方便记忆和使用)
2.静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新对象。(例如:单例)
例:Boolean.valueOf(boolean);
实例受控的类:原因:确保唯一或不可实例化。
3.静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类类型的对象。
4.静态工厂方法与构造器不同的第四大优势在于,在创建参数化类型实例的时候,它们使代码变得更加简洁。
复杂的:Map<String, List<String>> m = new HashMap<String, List<String>>();
假设HashMap提供了如下的静态工厂:
public static <K, V> HashMap<K, V> newInstance(){
return new HashMap<K, V>();
}
Map<String, List<String>> m = HashMap.newInstance();
5.静态工厂方法的主要缺点在于,类如果不含公有的或者受保护的构造器,就不能被子类化
6.静态工厂方法的第二个缺点在于,它们与其他的静态方法实际上没有任何区别。
valueOf、of、getInstance、newInstance、getType、newType
第二条:遇到多个构造器参数时要考虑用构造器
静态工厂和构造器有个共同的局限性:它们都不能很好地扩展到大量的可选参数。
面对必须的参数和可选的参数的构造器:
1.习惯采用重叠构造器
写多个构造器,第一个是必须参数的构造器,第二个是必须参数加上一个可选参数组成的构造器,第三个是必须参数加上两个个可选参数组成的构造器....
重叠构造器模式可行,但是当有许多参数的时候,客户端代码会比较难写,并且难以阅读。
2.采用javaBeans模式
创建一个无参的构造器,然后利用setter方法来设置必须的参数以及每个相关的可选参数。
javaBeans模式自身的缺点:
1.构造过程被分到几个调用中,在构造过程中JavaBean可能处于不一致的状态。类无法仅仅通过检验构造器参数的有效性来保证一致性。
2.JavaBeans模式阻止了类做成不可变的可能。这可能需要程序员付出额外的努力来确保它的线程安全。
3.采用Builder模式
既能保证像重叠构造器模式那样的安全性,也能保证像JavaBeans模式那么好的可读性。 不直接生成想要的对象,而是让客户端利用所有必要的参数调用构造器(或静态工厂),得到一个builder对象。然后客户端在builser对象上调用类似于setter的方法,来设置每个相关的可选参数。最后,客户端调用午餐的builder方法来生成不可变的对象。
示例:
package unit.test.no2; public class NutritionFacts { private final int servingSize; private final int servings; private final int calories; private final int fat; private final int sodium; private final int carbohydrate; public static class Builder{ //Required parameters private final int servingSize; private final int servings; //Optional parameters - initialized to default values private int calories = 0; private int fat = 0; private int sodium = 0; private int carbohydrate = 0; public Builder(int servingSize, int servings){ this.servingSize = servingSize; this.servings = servings; } public Builder calories(int val) { calories =val; return this; } public Builder fat(int val) { fat =val; return this; } public Builder sodium(int val) { sodium =val; return this; } public Builder carbohydrate(int val) { carbohydrate =val; return this; } public NutritionFacts build() { return new NutritionFacts(this); } } public NutritionFacts(Builder builder) { servingSize = builder.servingSize; servings = builder.servings; calories = builder.calories; fat = builder.fat; sodium = builder.sodium; carbohydrate = builder.carbohydrate; } }