深入理解设计模式-建造者模式(生成器模式)
文章目錄
- 一、什么是建造者模式
- 二、使用場景
- 三、簡單建造者模式
- 四、傳統建造者模式
- 結尾
一、什么是建造者模式
建造者模式也稱為生成器模式(英文:Builder Pattern),他可以將復雜對象的建造過程抽象出來,使這個抽象過程的不同實現方法可以構造出不同表現的對象。
二、使用場景
當一個類的構造函數參數個數超過4個,而且這些參數有些是可選的參數,考慮使用構造者模式。
當一個類的構造函數參數超過4個,而且這些參數有些是可選的時,我們通常有兩種辦法來構建它的對象。 例如我們現在有如下一個類計算機類Computer,其中cpu與ram是必填參數,而其他3個是可選參數,那么我們如何構造這個類的實例呢,通常有兩種常用的方式:
public class Computer {
private String cpu;//必須
private String ram;//必須
private int usbCount;//可選
private String keyboard;//可選
private String display;//可選
}
常用方式1:折疊構造函數模式(telescoping constructor pattern ),這個我們經常用,如下代碼所示
public class Computer {...public Computer(String cpu, String ram) {this(cpu, ram, 0);}public Computer(String cpu, String ram, int usbCount) {this(cpu, ram, usbCount, "羅技鍵盤");}public Computer(String cpu, String ram, int usbCount, String keyboard) {this(cpu, ram, usbCount, keyboard, "三星顯示器");}public Computer(String cpu, String ram, int usbCount, String keyboard, String display) {this.cpu = cpu;this.ram = ram;this.usbCount = usbCount;this.keyboard = keyboard;this.display = display;} }常用方式2:Javabean 模式,如下所示
public class Computer {...public String getCpu() {return cpu;}public void setCpu(String cpu) {this.cpu = cpu;}public String getRam() {return ram;}public void setRam(String ram) {this.ram = ram;}public int getUsbCount() {return usbCount;} ... }那么這兩種方式有什么弊端呢?
第一種主要是使用及閱讀不方便。你可以想象一下,當你要調用一個類的構造函數時,你首先要決定使用哪一個,然后里面又是一堆參數,如果這些參數的類型很多又都一樣,你還要搞清楚這些參數的含義,很容易就傳混了。。。那酸爽誰用誰知道。
第二種方式在構建過程中對象的狀態容易發生變化,造成錯誤。因為那個類中的屬性是分步設置的,所以就容易出錯。
為了解決這兩個痛點,builder模式就橫空出世了。
三、簡單建造者模式
在Computer 中創建一個靜態內部類 Builder,然后將Computer 中的參數都復制到Builder類中。
在Computer中創建一個private的構造函數,參數為Builder類型
在Builder中創建一個public的構造函數,參數為Computer中必填的那些參數,cpu 和ram。
在Builder中創建設置函數,對Computer中那些可選參數進行賦值,返回值為Builder類型的實例
在Builder中創建一個build()方法,在其中構建Computer的實例并返回
代碼樣例如下:
構建者模式是一個非常實用而常見的創建類型的模式(creational design pattern),例如圖片處理框架Glide,網絡請求框架Retrofit等都使用了此模式。
上面的內容是Builder在Java中一種簡化的使用方式,經典的Builder 模式與其有一定的不同,下面介紹傳統建造者模式。
四、傳統建造者模式
構建者模式UML圖如下所示:
如上圖所示,builder模式有4個角色。
Product: 最終要生成的對象,例如 Computer實例。
Builder: 構建者的抽象基類(有時會使用接口代替)。其定義了構建Product的抽象步驟,其實體類需要實現這些步驟。其會包含一個用來返回最終產品的方法Product getProduct()。
ConcreteBuilder: Builder的實現類。
Director: 決定如何構建最終產品的算法. 其會包含一個負責組裝的方法void Construct(Builder builder), 在這個方法中通過調用builder的方法,就可以設置builder,等設置完成后,就可以通過builder的 getProduct() 方法獲得最終的產品。
我們接下來將最開始的例子使用傳統方式來實現一遍。
第一步:我們的目標Computer類:
public class Computer {private String cpu;//必須private String ram;//必須private int usbCount;//可選private String keyboard;//可選private String display;//可選public Computer(String cpu, String ram) {this.cpu = cpu;this.ram = ram;}public void setUsbCount(int usbCount) {this.usbCount = usbCount;}public void setKeyboard(String keyboard) {this.keyboard = keyboard;}public void setDisplay(String display) {this.display = display;}@Overridepublic String toString() {return "Computer{" +"cpu='" + cpu + '\'' +", ram='" + ram + '\'' +", usbCount=" + usbCount +", keyboard='" + keyboard + '\'' +", display='" + display + '\'' +'}';} }第二步:抽象構建者類
public abstract class ComputerBuilder {public abstract void setUsbCount();public abstract void setKeyboard();public abstract void setDisplay();public abstract Computer getComputer(); }第三步:實體構建者類,我們可以根據要構建的產品種類產生多了實體構建者類,這里我們需要構建兩種品牌的電腦,蘋果電腦和聯想電腦,所以我們生成了兩個實體構建者類。
蘋果電腦構建者類
public class MacComputerBuilder extends ComputerBuilder {private Computer computer;public MacComputerBuilder(String cpu, String ram) {computer = new Computer(cpu, ram);}@Overridepublic void setUsbCount() {computer.setUsbCount(2);}@Overridepublic void setKeyboard() {computer.setKeyboard("蘋果鍵盤");}@Overridepublic void setDisplay() {computer.setDisplay("蘋果顯示器");}@Overridepublic Computer getComputer() {return computer;} }聯想電腦構建者類
public class LenovoComputerBuilder extends ComputerBuilder {private Computer computer;public LenovoComputerBuilder(String cpu, String ram) {computer=new Computer(cpu,ram);}@Overridepublic void setUsbCount() {computer.setUsbCount(4);}@Overridepublic void setKeyboard() {computer.setKeyboard("聯想鍵盤");}@Overridepublic void setDisplay() {computer.setDisplay("聯想顯示器");}@Overridepublic Computer getComputer() {return computer;} }第四步:指導者類(Director)
public class ComputerDirector {public void makeComputer(ComputerBuilder builder){builder.setUsbCount();builder.setDisplay();builder.setKeyboard();} }首先生成一個director (1),然后生成一個目標builder (2),接著使用director組裝builder (3),組裝完畢后使用builder創建產品實例 (4)。
public static void main(String[] args) {ComputerDirector director=new ComputerDirector();//1ComputerBuilder builder=new MacComputerBuilder("I5處理器","三星125");//2director.makeComputer(builder);//3Computer macComputer=builder.getComputer();//4System.out.println("mac computer:"+macComputer.toString());ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7處理器","海力士222");director.makeComputer(lenovoBuilder);Computer lenovoComputer=lenovoBuilder.getComputer();System.out.println("lenovo computer:"+lenovoComputer.toString()); }可以看到,文章最開始的使用方式是傳統builder模式的變種, 首先其省略了director 這個角色,將構建算法交給了client端,其次將builder 寫到了要構建的產品類里面,最后采用了鏈式調用。
結尾
- 感謝大家的耐心閱讀,如有建議請私信或評論留言。
- 如有收獲,勞煩支持,關注、點贊、評論、收藏均可,博主會經常更新,與大家共同進步
總結
以上是生活随笔為你收集整理的深入理解设计模式-建造者模式(生成器模式)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 双线性映射:零知识证明的引擎
- 下一篇: 高性能 DotNetty Server