一、建造者模式簡介
1.1、定義
建造者模式指將一個複雜的對象構造過程和對象的表示進行分離。使同樣的建造過程可以創建不同的表示,將構建過程拆分成多個簡單的對象,將不變和變進行分離。不變的是對象的組成部分,變化的是每個部分的具體內容。
比如建造汽車的過程,不變的是都需要車身、底盤、車輪、發動機等組件,變化的是每個組件可以有不同的構造過程。
1.2、優缺點
a.封裝性好,構建和表示進行分離
b.擴展性好,各個具體的建造者相互獨立,各個組件之間互相解耦
c.對象調用者無需關係對象的具體建造過程,滿足迪米特法則
1.3、建造者模式的角色
產品:需要建造的對象,通常包含是由多個簡單的組件組合成的複雜對象
抽象建造者:包含創建產品各個子部件的抽象方法的接口,通過還包含一個返回複雜對象的方法用於返回建造後的對象
具體建造者:實現抽象建造者,完成複雜產品各個子部件的具體創建
指揮者:調用建造者對象中的部件構造方法與裝配方法完成複雜對象的創建,指揮者不關心具體產品的信息
二、建造者模式案例
1、業務場景
構造一個汽車對象,汽車對象包含了車身、底盤、發動機、車輪等核心組件
2、代碼實現
a.定義汽車對象及各個組件的實體類
1 /** 2 * 汽車類 3 */ 4 public class Car { 5 6 //車架 7 private CarFrame frame; 8 9 //發動機 10 private Engine engine; 11 12 //底盤 13 private Chassis chassis; 14 15 //車輪 16 private Wheel wheel; 17 18 public CarFrame getFrame() { 19 return frame; 20 } 21 22 public void setFrame(CarFrame frame) { 23 this.frame = frame; 24 } 25 26 public Engine getEngine() { 27 return engine; 28 } 29 30 public void setEngine(Engine engine) { 31 this.engine = engine; 32 } 33 34 public Chassis getChassis() { 35 return chassis; 36 } 37 38 public void setChassis(Chassis chassis) { 39 this.chassis = chassis; 40 } 41 42 public Wheel getWheel() { 43 return wheel; 44 } 45 46 public void setWheel(Wheel wheel) { 47 this.wheel = wheel; 48 } 49 }
b.定義抽象建造者,提供返回對象的方法並定義汽車對象構建各個子部件的抽象
1 /** 2 * 抽象汽車建造者 3 */ 4 public abstract class CarBuilder { 5 6 protected Car car = new Car(); 7 8 /** 返回構造的汽車對象*/ 9 public Car builder(){ 10 return car; 11 } 12 13 /** 構建車架*/ 14 public abstract CarBuilder frame(); 15 16 /** 構建發動機*/ 17 public abstract CarBuilder engine(); 18 19 /** 構建底盤*/ 20 public abstract CarBuilder chassis(); 21 22 /** 構建車輪*/ 23 public abstract CarBuilder wheel(); 24 }
c.實現具體的建造者,如奔馳汽車建造者
1 /** 2 * 奔馳汽車建造者實現類 3 */ 4 public class BenzCarBuilder extends CarBuilder{ 5 6 @Override 7 public CarBuilder frame() { 8 System.out.println("奔馳建造者構建車輪"); 9 car.setFrame(new CarFrame("奔馳車輪")); 10 return this; 11 } 12 13 @Override 14 public CarBuilder engine() { 15 System.out.println("奔馳建造者構建發動機"); 16 car.setEngine(new Engine("奔馳發動機")); 17 return this; 18 } 19 20 @Override 21 public CarBuilder chassis() { 22 System.out.println("奔馳建造者構建底盤"); 23 car.setChassis(new Chassis("奔馳底盤")); 24 return this; this; 25 } 26 27 @Override 28 public CarBuilder wheel() { 29 System.out.println("奔馳建造者構建車輪"); 30 car.setWheel(new Wheel("奔馳車輪")); 31 return this; 32 } 33 }
測試代碼如下:
1 public static void main(String[] args){ 2 CarBuilder builder = new BenzCarBuilder(); 3 /** 通過奔馳建造者構建汽車對象 */ 4 Car car = builder.frame().engine().chassis().builder(); 5 System.out.println(JSON.toJSONString(car)); 6 }
1 奔馳建造者構建車輪 2 奔馳建造者構建發動機 3 奔馳建造者構建底盤 4 {"chassis":{"name":"奔馳底盤"},"engine":{"name":"奔馳發動機"},"frame":{"name":"奔馳車輪"}}
調用方main函數中無需關心汽車是如何構建的,只需要關心需要將哪些組件組合到汽車對象上。如果汽車需要增加或者刪除一些組件,只需要在抽象建造者中增加或刪除對應的方法即可,比如需要添加儀表盤組件,則只需要定義儀表盤對象,並且在抽象建造者中添加對應的方法即可,代碼如下:
定義儀表盤類DashBoard類,並在Car中添加屬性,修改抽象建造者類,添加構造儀表盤的方法
1 /** 2 * 抽象汽車建造者 3 */ 4 public abstract class CarBuilder { 5 6 protected Car car = new Car(); 7 8 /** 返回構造的汽車對象*/ 9 public Car builder(){ 10 return car; 11 } 12 13 /** 構建車架*/ 14 public abstract CarBuilder frame(); 15 16 /** 構建發動機*/ 17 public abstract CarBuilder engine(); 18 19 /** 構建底盤*/ 20 public abstract CarBuilder chassis(); 21 22 /** 構建車輪*/ 23 public abstract CarBuilder wheel(); 24 25 /** 構建儀表盤*/ 26 public abstract CarBuilder bashBoard(); 27 }
此時構造汽車時就可以加上儀表盤的構造
1 public static void main(String[] args){ 2 CarBuilder builder = new BenzCarBuilder(); 3 /** 通過奔馳建造者構建汽車對象 */ 4 Car car = builder.frame().engine().chassis().bashBoard().builder(); 5 System.out.println(JSON.toJSONString(car)); 6 }
另外本例子中的具體建造者是直接實現了構建細節,還可以改造成將構建細節分離,將構建的組件進行抽象化,比如將上例中的需求改動,汽車不再由奔馳建造者來建造,而是由一個第三方建造者來構建,第三方建造者造汽車時可能會用保時捷的發動機、奔馳的車身、寶馬的底盤和奧迪的儀表盤,此時將構建細節交給具體建造者的化就不好擴展,所以具體建造者應該將構建組件的部分抽象分離出去。代碼如下:
將各個組件抽象化
/** * 車架組件 */ public interface CarFrame { public String name(); } /** * 底盤組件 */ public interface Chassis { public String name(); } /** * 發動機組件 */ public interface Engine { public String name(); } /** * 車輪組件 */ public interface Wheel { public String name(); } /** * 儀表盤抽象 */ public interface BashBoard { public String name(); }
修改抽象建造者類,此時由於組件是直接由外部構建,那麼可以直接去除建造者類的抽象定義,直接由建造者類構建即可,代碼如下:
1 /** 2 * 抽象汽車建造者 3 */ 4 public class CarBuilder { 5 6 protected Car car = new Car(); 7 8 /** 返回構造的汽車對象*/ 9 public Car builder(){ 10 return car; 11 } 12 13 /** 構建車架*/ 14 public CarBuilder frame(CarFrame carFrame){ 15 car.setFrame(carFrame); 16 return this; 17 } 18 19 /** 構建發動機*/ 20 public CarBuilder engine(Engine engine){ 21 car.setEngine(engine); 22 return this; 23 } 24 25 /** 構建底盤*/ 26 public CarBuilder chassis(Chassis chassis){ 27 car.setChassis(chassis); 28 return this; 29 } 30 31 /** 構建車輪*/ 32 public CarBuilder wheel(Wheel wheel){ 33 car.setWheel(wheel); 34 return this; 35 } 36 37 /** 構建儀表盤*/ 38 public CarBuilder bashBoard(BashBoard bashBorad){ 39 car.setBashBoard(bashBorad); 40 return this; 41 } 42 }
測試代碼如下:
1 public static void main(String[] args){ 2 CarBuilder builder = new CarBuilder(); 3 /** 通過建造者類構建汽車對象 */ 4 Car car = builder 5 .frame(new BenzFrame())//奔馳車架 6 .engine(new PorscheEngine())//保時捷發動機 7 .chassis(new BmwChassis())//寶馬底盤 8 .bashBoard(new AudiBashBoard())//奧迪儀表盤 9 .wheel(new MichelinWheel())//米其林車輪 10 .builder(); 11 System.out.println(car.toString()); 12 }
1 {"engine":"保時捷發動機","wheel":"米其林車輪","chassis":"寶馬底盤","bashBoard":"奧迪儀表盤","frame":"奔馳車架"}
兩種實現方式都各自有各自的優點,可以根據具體的業務場景選擇更方便的更具有擴展性的方式來實現。
三、建造者模式和工廠模式的對比
1、建造者不關注組件的生產過程,只關心複雜對象的構建過程;而工廠模式需要關心各個組件的生產過程;
2、建造者傾向於建造結構相同內容不同的對象;工廠模式傾向於批量生產結構相同且內容也相同的對象;
3、建造者模式中客戶端可以控制如何構造對象的組件;工廠模式中客戶端無法控制構建對象的細節;
可以表示中建造者模式更加註重的是創建對象的過程;工廠模式更加註重的是創建對象的結果。