一、用靜態工廠方法代替構造器
靜態工廠方法與構造器相比有以下幾個優點:
- 靜態工廠方法有名稱;
- 不必每次調用的時候都創建新的對象;
- 可以返回原返回類型的任何子類型的對象;
- 在創建參數化類型實例的時候沒,靜態工廠方法使得代碼變得更加簡潔;
缺點:
- 類如果不含有公有的或者受保護的構造器,就不能被子類化;
- 靜態工廠方法與其他的靜態方法實際上並沒有任何區別;
靜態工廠方法常用的名稱:
- valueOf:一般用作類型轉換方法;
- of:valueOf更簡潔的代替,在EnumSet中使用病流行起來;
- getInstance:用於返回實例;
- newInstance:返回的實例與其他的所有實例都不同;
- getType:和newInstance類似;
代碼:https://github.com/yanzxu/EffectiveJava/tree/master/src/main/java/chapter1/staticfactory
public class Services {
private Services() {
}
private static final Map<String, Provider> providers = new ConcurrentHashMap<>();
private static final String DEFAULT_PROVIDER_NAME = "test";
public static void registerDefaultProvider(Provider provider) {
registerProvider(DEFAULT_PROVIDER_NAME, provider);
}
public static void registerProvider(String name, Provider prodiver) {
providers.put(name,prodiver);
}
public static Service newInstance() {
return newInstance(DEFAULT_PROVIDER_NAME);
}
public static Service newInstance(String name){
Provider p = providers.get(name);
if (p == null) throw new IllegalArgumentException("No provider registered with name: " + name);
return p.newService();
}
}
二、遇到多個構造器參數時考慮用構造器Builder模式
情景
對於多參構造器,其中一些參數是必須的而另一些則是可選的,這樣的話我們在創建類的時候就要創建多個含有不同參數的構造器,不僅笨重而且不易區分不同的構造器,針對這種情況我們就可以採用Builder模式來替代多參構造器,如下所示。
代碼 https://github.com/yanzxu/EffectiveJava/tree/master/src/main/java/chapter1/builder
public class Person {
private String name;
private boolean gender;
private int age;
private String address;
private Date birthday;
private Person(Builder builder){
this.name = builder.name;
this.gender = builder.gender;
this.age = builder.age;
this.address = builder.address;
this.birthday= builder.birthday;
}
public static class Builder {
// required parameters
private String name;
private boolean gender;
// optional parameters: initialized to default values
private int age = 0;
private String address = "China";
private Date birthday = new Date();
public Builder(String name, boolean gender) {
this.name = name;
this.gender = gender;
}
public Builder age(int age) {
this.age= age;
return this;
}
public Builder address(String address) {
this.address= address;
return this;
}
public Builder birthday(Date birthday) {
this.birthday= birthday;
return this;
}
public Person build() {
return new Person(this);
}
}
}
創建對象
此時創建對象只需要傳入必選參數就可以了。
new Person.Builder("Eric", true)
.age(22)
.address("Beijing")
.build();