Builder模式
創建一個entity或者javabean通常使用三種方法。
- 使用無參構造函數,用setter方法來設置對象的初始值。
- 使用帶參構造函數,通過構造函數來初始化參數
- 使用builder設計模式創建對象。
如果使用常用的getter/setter方法,那么通常在構造一個我們需要的對象時,使用一長串的setter方法,並且該對象也變成是可變的,即可以使用setter方法隨意的修改對象的狀態。
使用帶參構造函數能夠避免創建可變的對象,但是需要大量的構造函數,要想考慮到每一種情況,構造函數的數量需要用排練組合來計算,或者是創建一個包含全部參數的構造函數,當我們不關注該對象的某個屬性時,通過給它設置個默認值即可,通常是null,0,false等。但是當存在大量的參數時,會出現很難把值與變量的位置匹配起來,給閱讀與書寫帶來大量的麻煩。
為了避免上述的情況,我們可以使用builder模式來創建一個java對象。主要是利用靜態內部類的方式。
見代碼如下:
package com.manager.design;
public class Student2 {
private final int id;
private final String name;
private int age;
private Student2(){} //定義私有構造器,只能在類內部使用(提供給靜態內部類創建一個對象)
private Student2(Student2 origin){ // 拷貝一個對象,即把靜態內部類對象的屬性給外部類,由靜態內部類調用
this.id = origin.id;
this.name = origin.name;
this.age = origin.age;
}
public int getId(){
return this.id;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public static class Builder{ //靜態內部類,通過該類來創建一個外部類對象,使用鏈式調用
private Student2 target; //創建一個外部類對象
/**
* 構造一個內部類對象,通過該對象設置屬性值
* 如果存在必填參數,可以以帶參構造函數的方式傳過來
* @param id 必填參數
* @param name 必填參數
*/
public Builder(int id , String name){
target= new Student2();
target.id = id;
target.name = name;
}
/**
* 調動builder對象的id方法設置id值
* 返回builder對象,用來下一個方法設置屬性值
* 這就是鏈式調用
* @param id
* @return
*/
public Builder age(int age){
target.age = age;
return this;
}
/**
*
* @return
*/
public Student2 build(){
Student2 st = new Student2(target); //調用外部類的帶參構造函數初始化外部類的參數
if(st.id < 100) //builder模式是線性不安全的,所以我們必須要類創建完畢后才能對異常處理
try{
throw new IllegalStateException("Age out of range"); // 非線程安全
}
catch( IllegalStateException e){
st.id = 1000;
e.printStackTrace();
}
return st; //返回一個外部類
}
}
public static void main(String [] args){
Student2 st = new Student2.Builder(1, "hubin").id(23).build();
System.out.println(st.getId());
}
}
注:
1. builder模式中的構造函數都是私有的,不允許外部調用
2. builder模式中只有getter方法,沒有setter方法
3. builder模式中使用了鏈式調用,更具有可讀性
4. 對於一個對象如果需要傳入必填參數,則可以在構造函數中傳入參數,且類對應的參數應當有fianl修飾,如果沒有,如下代碼中id,name作為參數傳入毫無意義,因為仍然可以被修改。
public Builder(int id , String name){
target= new Student2();
target.id = id;
target.name = name;
}
public Builder id(int id){
target.id = id;
return this;
}
public Builder name(String name){
target.name = name;
return this;
}