JAVA常用設計模式3--建造者模式

一、建造者模式簡介

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、建造者模式中客戶端可以控制如何構造對象的組件;工廠模式中客戶端無法控制構建對象的細節;

可以表示中建造者模式更加註重的是創建對象的過程;工廠模式更加註重的是創建對象的結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章