建造者模式(Builder Pattern)也叫做生成器模式,是 GoF 的 23 種設計模式的一種,它將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
當我們需要實列化一個復雜的類,以得到不同結構類型和不同的內部狀態的對象時,我們可以用不同的類對它們的實列化操作邏輯分別進行封裝,這些類我們就稱之為建造者。
~
本篇內容包括:關于建造者模式、建造者模式 Demo、使用建造者模式進行重構
文章目錄
- 一、關于建造者模式
- 1、關于建造者模式
- 2、關于建造者模式的構成
- 3、關于建造者模式的優缺點
- 4、關于建造者模式與工廠模式區別
- 二、建造者模式 Demo
- 1、Demo 設計
- 2、Demo 實現
- 3、Demo 測試
- 三、使用建造者模式進行重構
- 1、重構前代碼
- 2、重構前使用
- 3、重構后代碼
- 4、重構后使用
一、關于建造者模式
1、關于建造者模式
建造者模式(Builder Pattern)也叫做生成器模式,是 GoF 的 23 種設計模式的一種,它將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可以創建不同的表示。
當我們需要實列化一個復雜的類,以得到不同結構類型和不同的內部狀態的對象時,我們可以用不同的類對它們的實列化操作邏輯分別進行封裝,這些類我們就稱之為建造者。
當我們需要來自同一個類,但是要就有不同結構對象時,就可以通過構造另一個建造者來進行實列化。
建造者(Builder)模式創建的是復雜對象,其產品的各個部分經常面臨著劇烈的變化,但將它們組合在一起的算法卻相對穩定,所以它通常在以下場合使用。
- 創建的對象較復雜,由多個部件構成,各部件面臨著復雜的變化,但構件間的建造順序是穩定的。
- 創建復雜對象的算法獨立于該對象的組成部分以及它們的裝配方式,即產品的構建過程和最終的表示是獨立的。
2、關于建造者模式的構成
建造者模式包含如下角色:
- 抽象建造者類(Builder):這個接口規定要實現包含創建產品各個子部件的抽象方法以及返回復雜產品的方法,并不涉及具體的部件對象的創建。
- 具體建造者類(ConcreteBuilder):實現抽象 Builder 定義的所有方法,并且返回一個裝配好的對象。
- 產品類(Product):一般是多個部件組成的復雜對象,由具體建造者來創建其各個零部件。
- 指揮者類(Director):負責安排已有模塊的順序,然后調用 Builder 建造產品。
3、關于建造者模式的優缺點
# 優點
- 封裝性,在建造者模式中,調用方不必知道產品內部組成的細節,將一個復雜對象的構建與它的表示分離,使得相同的創建過程可以創建不同的產品對象。
- 擴展性,每個具體建造者都相互獨立,替換具體建造者或新增具體建造者都很便捷。
- 更關注 “由零件一步一步地組裝出產品對象”。將復雜產品的創建步驟拆分到不同的方法中,使得創建過程更加清晰。
# 缺點
- 建造者模式所創建的產品對象一般組成部分相似,如果產品的內部變化復雜,需要定義很多具體建造者類來實現這種變化,導致系統變得很龐大。
- 如果產品內部結構發生變化,建造者也要相應修改,有較大的維護成本。
4、關于建造者模式與工廠模式區別
- 工廠模式,一般都是創建一個產品,注重的是把這個產品創建出來就行,只要創建出來,不關心這個產品的組成部分。從代碼上看,工廠模式就是一個方法,用這個方法就能生產出產品。,,
- 建造者模式,也是創建一個產品,但是不僅要把這個產品創建出來,還要關系這個產品的組成細節,組成過程。 從代碼上看,建造者模式在建造產品時,這個產品有很多方法,建造者模式會根據這些相同方法但是不同執行順序建造出不同組成細節的產品。
二、建造者模式 Demo
1、Demo 設計
生產汽車是一個復雜的過程,它包含了車架,車座等等組件的生產,而車架又有碳纖維,鋁合金等材質的,車座有橡膠,真皮等材質。對于汽車的生產就可以使用建造者模式。
2、Demo 實現
# Car 產品類
public class Car {/*** 車架*/private String frame;/*** 座椅*/private String seat;public String getFrame() {return frame;}public void setFrame(String frame) {this.frame = frame;}public String getSeat() {return seat;}public void setSeat(String seat) {this.seat = seat;}
}
# Builder 抽象建造者類
public abstract class Builder {protected Car car = new Car();/*** 建造車架*/public abstract void buildFrame();/*** 建造座椅*/public abstract void buildSeat();/*** 造車** @return Car*/public abstract Car createCar();
}
# ACarBulider 具體建造者類
public class ACarBuilder extends Builder {@Overridepublic void buildFrame() {car.setFrame("鋁合金車架");}@Overridepublic void buildSeat() {car.setSeat("真皮車座");}@Overridepublic Car createCar() {return car;}
}
# BCarBulider 具體建造者類
public class BCarBuilder extends Builder {@Overridepublic void buildFrame() {car.setFrame("碳纖維車架");}@Overridepublic void buildSeat() {car.setSeat("皮革車座");}@Overridepublic Car createCar() {return car;}
}
# Director 指揮者類
public class Director {private final Builder mBuilder;public Director(Builder builder) {mBuilder = builder;}public Car construct() {mBuilder.buildFrame();mBuilder.buildSeat();return mBuilder.createCar();}
}
3、Demo 測試
public class Client {private static void showCar(Builder builder) {Director director = new Director(builder);Car car = director.construct();System.out.println(car.getFrame());System.out.println(car.getSeat());}public static void main(String[] args) {showCar(new ACarBuilder());showCar(new BCarBuilder());}}
三、使用建造者模式進行重構
建造者模式除了上面的用途外,在開發中還有一個常用的使用方式,就是當一個類構造器需要傳入很多參數時,如果創建這個類的實例,代碼可讀性會非常差,而且很容易引入錯誤,此時就可以利用建造者模式進行重構。
1、重構前代碼
public class Phone {private String cpu;private String screen;private String memory;private String mainboard;public Phone(String cpu, String screen, String memory, String mainboard) {this.cpu = cpu;this.screen = screen;this.memory = memory;this.mainboard = mainboard;}public String getCpu() {return cpu;}public void setCpu(String cpu) {this.cpu = cpu;}public String getScreen() {return screen;}public void setScreen(String screen) {this.screen = screen;}public String getMemory() {return memory;}public void setMemory(String memory) {this.memory = memory;}public String getMainboard() {return mainboard;}public void setMainboard(String mainboard) {this.mainboard = mainboard;}@Overridepublic String toString() {return "Phone{" +"cpu='" + cpu + '\'' +", screen='" + screen + '\'' +", memory='" + memory + '\'' +", mainboard='" + mainboard + '\'' +'}';}}
2、重構前使用
public class Client {public static void main(String[] args) {//構建Phone對象Phone phone = new Phone("intel", "三星屏幕", "金士頓", "華碩");System.out.println(phone);}
}
3、重構后代碼
public class Phone {private String cpu;private String screen;private String memory;private String mainboard;private Phone(Builder builder) {cpu = builder.cpu;screen = builder.screen;memory = builder.memory;mainboard = builder.mainboard;}public static final class Builder {private String cpu;private String screen;private String memory;private String mainboard;public Builder() {}public Builder cpu(String val) {cpu = val;return this;}public Builder screen(String val) {screen = val;return this;}public Builder memory(String val) {memory = val;return this;}public Builder mainboard(String val) {mainboard = val;return this;}public Phone build() {return new Phone(this);}}@Overridepublic String toString() {return "Phone{" +"cpu='" + cpu + '\'' +", screen='" + screen + '\'' +", memory='" + memory + '\'' +", mainboard='" + mainboard + '\'' +'}';}
}
4、重構后使用
public class Client {public static void main(String[] args) {Phone phone = new Phone.Builder().cpu("intel").mainboard("華碩").memory("金士頓").screen("三星").build();System.out.println(phone);}
}