【設計模式】創建型-建造者模式

前言

在面向對象的軟件開發中,構建復雜對象時經常會遇到許多挑戰。一種常見的解決方案是使用設計模式,其中建造者模式是一個強大而靈活的選擇。本文將深入探討建造者模式的原理、結構、優點以及如何在實際項目中應用它。

一、復雜的對象

public class Computer {private String ram;private String hardDisk;private String cpu;// ...可能還有更多參數...public Computer(String ram, String hardDisk, String cpu) {this.ram = ram;this.hardDisk = hardDisk;this.cpu = cpu;// ...初始化更多參數...}// getters and setters...
}// 使用構造函數創建對象,參數多且容易混淆
Computer computer = new Computer("16GB", "1TB", "Intel i7");

上面代碼比較簡單,但是如果 Computer 類有更多的參數,構造函數將會變得非常長,而且在創建 Computer 對象時,傳遞參數的順序非常重要,一旦順序錯誤,就會創建出一個配置錯誤的對象。此外,如果參數有默認值,那么用戶還需要記住哪些參數是必須的,哪些是可選的,這增加了使用的復雜性。

我們可以總結出創建復雜對象時可能會遇到的問題包括:

  1. 參數過多:構造函數或者 setter 方法的參數可能會非常多,導致代碼難以閱讀和維護。
  2. 參數順序:容易混淆參數的順序,特別是當有多個相同類型的參數時。
  3. 不夠靈活:如果創建過程中需要多個步驟,使用構造函數或 setter 方法就不夠靈活。
  4. 不可讀性:代碼的可讀性差,特別是在沒有注釋的情況下,很難理解每個參數的意義。

二、建造者模式

建造者模式是一種創建型設計模式,旨在將復雜對象的構建過程與其表示分離。通過使用建造者模式,可以使客戶端代碼與對象的內部結構解耦,從而使構建過程更加靈活,并且更易于維護和擴展。

三、建造者模式的核心組成部分

在這里插入圖片描述

建造者模式通常包括以下幾個關鍵組件:

  1. 產品(Product):表示被構建的復雜對象。產品類通常包含多個屬性,并且可能包含一些復雜的業務邏輯。
  2. 抽象建造者(Builder):定義了構建產品所需的接口。抽象建造者通常包括一系列方法來構建產品的各個部分。
  3. 具體建造者(Concrete Builder):實現了抽象建造者接口,負責實際構建產品的各個部分,并提供方法來獲取最終的產品實例。
  4. 指揮者(Director):負責調用建造者的方法來構建產品,但不直接創建產品的實例。指揮者通常根據一定的構建步驟來組織構建過程。

四、運用建造者模式

場景假設:我們要構建一臺計算機,它有不同的部件,比如 CPU、內存、硬盤等。我們將使用建造者模式來構建這臺計算機。

  1. 定義產品類: 首先,確定需要構建的復雜對象的屬性和方法,并創建相應的產品類。這個產品類應該包含對象的所有屬性,并提供相應的 getter 和 setter 方法。

    /*** 產品類:計算機*/
    public class Computer {private String cpu;       // CPUprivate String memory;    // 內存private String hardDisk;  // 硬盤// 省略構造函數和 getter/setter方法
    }
    
  2. 創建抽象建造者接口: 定義一個抽象建造者接口,該接口包含構建產品各個部件的抽象方法。這些方法代表構建產品所需的不同步驟。

    /*** 抽象建造者接口*/
    public interface ComputerBuilder {// 構建CPUvoid buildCPU();// 構建內存void buildMemory();// 構建硬盤void buildHardDisk();// 構建計算機Computer build();
    }
    
  3. 實現具體建造者類: 創建一個或多個具體建造者類,實現抽象建造者接口。每個具體建造者類負責實現構建產品各個部件的具體方法,并在最后返回構建好的產品。

    /*** 具體建造者類:桌面計算機建造者*/
    public class DesktopComputerBuilder implements ComputerBuilder {private Computer computer;  // 待構建的計算機對象public DesktopComputerBuilder() {this.computer = new Computer();}@Overridepublic void buildCPU() {computer.setCpu("Intel Core i7");}@Overridepublic void buildMemory() {computer.setMemory("16GB DDR4");}@Overridepublic void buildHardDisk() {computer.setHardDisk("1TB SSD");}@Overridepublic Computer build() {// 返回構建好的計算機對象return computer;}
    }
    
  4. 創建指揮者類: 定義一個指揮者類,該類負責使用具體建造者對象構建最終的產品。指揮者類知道構建者的具體實現細節,但與產品的實際構建過程無關。

    /*** 指揮者類:計算機指揮者*/
    public class ComputerDirector {private ComputerBuilder computerBuilder;  // 建造者對象public ComputerDirector(ComputerBuilder computerBuilder) {this.computerBuilder = computerBuilder;}// 使用建造者構建計算機對象public Computer construct() {// 按照順序調用建造者的方法來構建計算機computerBuilder.buildCPU();computerBuilder.buildMemory();computerBuilder.buildHardDisk();// 返回構建好的計算機對象return computerBuilder.build();}
    }
    
  5. 使用建造者模式構建對象: 在客戶端代碼中,創建具體的建造者對象,并將其傳遞給指揮者類。然后,通過指揮者類調用相應的方法來構建產品。最終,客戶端代碼可以獲取構建好的產品并使用它。

    public class Main {public static void main(String[] args) {// 創建桌面計算機的建造者對象ComputerBuilder desktopBuilder = new DesktopComputerBuilder();// 創建計算機指揮者對象,并傳入桌面計算機的建造者ComputerDirector director = new ComputerDirector(desktopBuilder);// 使用指揮者構建計算機對象Computer desktop = director.construct();// 輸出構建好的桌面計算機的配置信息System.out.println("Desktop Computer Configuration:");System.out.println(desktop);}
    }/*在一些簡單的情況下,可以省略指揮者(Director)類。特別是當只有一個具體建造者(Concrete Builder)時,客戶端代碼可以直接調用具體建造者的方法來構建產品,而不需要指揮者類。
    */
    public class Main {public static void main(String[] args) {// 創建桌面計算機的建造者對象ComputerBuilder desktopBuilder = new DesktopComputerBuilder();// 使用桌面計算機的建造者直接構建計算機對象Computer desktop = desktopBuilder.buildCPU().buildMemory().buildHardDisk().build();// 輸出構建好的桌面計算機的配置信息System.out.println("Desktop Computer Configuration:");System.out.println(desktop);}
    }
    

在上面的例子中,我們定義了 Computer 類作為產品,ComputerBuilder 作為具體建造者來創建產品,ComputerDirector 作為指導者確定創建產品時遵循的步驟流程。客戶端代碼只需通過 ComputerDirector 便能構建 Computer 對象,這樣就隱藏了構建細節,使得客戶端代碼更加簡潔和易于維護。

五、建造者模式的應用場景

建造者模式適用于以下幾種場景:

  1. 復雜對象的創建:當創建的對象非常復雜,包含多個組成部分時,建造者模式可以幫助管理復雜性,使得代碼更加清晰。

    // 假設我們需要創建一個復雜的 Pizza 對象,它包含多種配料和選項。
    // 產品類
    public class Pizza {private String dough;private String sauce;private String topping;// 私有構造器private Pizza(Builder builder) {this.dough = builder.dough;this.sauce = builder.sauce;this.topping = builder.topping;}// Builder類public static class Builder {private String dough;private String sauce;private String topping;public Builder withDough(String dough) {this.dough = dough;return this;}public Builder withSauce(String sauce) {this.sauce = sauce;return this;}public Builder withTopping(String topping) {this.topping = topping;return this;}public Pizza build() {return new Pizza(this);}}
    }// 客戶端代碼
    // 在創建 Pizza 時,可以根據需要選擇是否設置 dough、sauce、topping
    Pizza pizza = new Pizza.Builder().withDough("cross").withSauce("mild").withTopping("ham and pineapple").build();
    
  2. 構造過程需要分步驟進行:如果一個對象的構造過程需要分多個步驟或者階段來完成,建造者模式允許你逐步構造對象,而不是一次性通過一個巨大的構造函數完成。

    // 倘若 House 對象的構建,需要分步驟設置地基、結構、屋頂和內部裝修。
    // 產品類
    public class House {private String foundation;private String structure;private String roof;private String interior;private House(Builder builder) {this.foundation = builder.foundation;this.structure = builder.structure;this.roof = builder.roof;this.interior = builder.interior;}// Builder類public static class Builder {private String foundation;private String structure;private String roof;private String interior;public Builder withFoundation(String foundation) {this.foundation = foundation;return this;}public Builder withStructure(String structure) {this.structure = structure;return this;}public Builder withRoof(String roof) {this.roof = roof;return this;}public Builder withInterior(String interior) {this.interior = interior;return this;}public House build() {return new House(this);}}
    }// 客戶端代碼
    // 在創建對象之前,可嚴格管控步驟的先后順序
    House house = new House.Builder().withFoundation("concrete").withStructure("wooden").withRoof("shingle").withInterior("painted").build();
    
  3. 同一構建過程不同表示:當需要根據不同的需求和過程來創建不同的對象表示時,建造者模式提供了很好的解決方案。

    // 如果我們有一個 Car 對象,它可以有不同的配置,例如經濟型和豪華型。
    // 產品類
    public class Car {private String engine;private String seats;private String navigationSystem;private Car(Builder builder) {this.engine = builder.engine;this.seats = builder.seats;this.navigationSystem = builder.navigationSystem;}// Builder類public static class Builder {private String engine;private String seats;private String navigationSystem;public Builder withEngine(String engine) {this.engine = engine;return this;}public Builder withSeats(String seats) {this.seats = seats;return this;}public Builder withNavigationSystem(String navigationSystem) {this.navigationSystem = navigationSystem;return this;}public Car build() {return new Car(this);}}
    }// 客戶端代碼
    // 根據不同配置,滿足不同需求
    Car economyCar = new Car.Builder().withEngine("1.5L").withSeats("cloth").build();Car luxuryCar = new Car.Builder().withEngine("3.0L V6").withSeats("leather").withNavigationSystem("advanced").build();
    
  4. 參數多且復雜:當構造函數的參數非常多,且有些可能是可選的,建造者模式可以幫助組織這些參數,使得構造函數不會過于龐大和復雜。

    // 倘若 Order 對象可能包含多個可選的配置項,如禮品包裝、快遞服務、優惠券等,
    // 使用建造者模式可以讓客戶端代碼清晰地指定所需的配置。
    // 產品類:具有多個配置參數,其中一些是可選的。
    public class Order {private String product;private boolean giftWrap;private boolean expressDelivery;private String couponCode;// 私有構造器,只能通過Builder類構建Order對象private Order(Builder builder) {this.product = builder.product;this.giftWrap = builder.giftWrap;this.expressDelivery = builder.expressDelivery;this.couponCode = builder.couponCode;}// Builder 類:提供了一個鏈式 API 來設置 Order 對象的屬性public static class Builder {private String product;private boolean giftWrap;private boolean expressDelivery;private String couponCode;public Builder(String product) {this.product = product;}public Builder setGiftWrap(boolean giftWrap) {this.giftWrap = giftWrap;return this;}public Builder setExpressDelivery(boolean expressDelivery) {this.expressDelivery = expressDelivery;return this;}public Builder setCouponCode(String couponCode) {this.couponCode = couponCode;return this;}// 構建方法:創建一個Order對象并返回public Order build() {return new Order(this);}}
    }// 客戶端使用:創建一個 Order 對象
    Order order = new Order.Builder("Product1").setGiftWrap(true).setExpressDelivery(true).setCouponCode("DISCOUNT10").build();
    

六、小結

建造者模式是一種創建復雜對象的有效方式,它允許我們按照步驟構建對象,從而使得構建過程更加靈活和可配置。例如,在 Java 中,StringBuilder 是建造者模式的一個典型應用,它允許我們通過多個方法調用來構建最終的字符串,而不是一次性傳入所有的字符串內容。另一個例子是流式 API,如 Java 8 的 Stream API,它允許通過鏈式調用來構建復雜的查詢。通過將構建過程與表示分離,建造者模式提高了代碼的可讀性和可維護性,同時也使得代碼更加易于擴展和重用。

推薦閱讀

  1. Spring 三級緩存
  2. 深入了解 MyBatis 插件:定制化你的持久層框架
  3. Zookeeper 注冊中心:單機部署
  4. 【JavaScript】探索 JavaScript 中的解構賦值
  5. 深入理解 JavaScript 中的 Promise、async 和 await

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20100.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20100.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20100.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

飛凌嵌入式FET3568/3568J-C核心板現已適配OpenHarmony4.1

近日,飛凌嵌入式為FET3568/3568J-C核心板適配了OpenHarmony4.1系統,新系統的加持使核心板在兼容性、穩定性與安全性等方面都得到進一步提升,不僅為FET3568/3568J-C核心板賦予了更強大的功能,也為開發者們提供了更加廣闊的創新空間…

每日一練編程題:今天是【接口,多態】

設計程序 : 電腦類的屬性USB接口數組 : 有3個usb插口電腦類的功能 : 通過接口插入外設 (u盤,麥克風,鍵盤等) addUSB(USB usb) { }開機 要求: 電腦開機前,先啟動外設關機 要求: 電腦關機前,先關閉外設 外設類(u盤,麥克風,鍵盤等) 功能 : 啟動 關閉 USB接口 定義usb設備的統一…

python多種方式 保留小數點位數(附Demo)

目錄 前言1. 字符串格式2. round函數3. Decimal模塊4. numpy庫5. Demo 前言 在Python中,保留小數點后特定位數可以通過多種方式實現 以下是幾種常見的方法,并附上相應的代碼示例: 使用字符串格式化(String Formatting&#xff…

IDE集成開發環境

IDE集成開發環境,全稱“Integrated Development Environment” 介紹 定義: IDE是用于提供程序開發環境的應用程序,它集成了代碼編寫功能、分析功能、編譯功能、調試功能等一體化的開發軟件服務套。 組成部分: IDE通常包括代碼編…

Ubuntu20.04 Mysql基本操作知識

#Mysql基本知識 運行環境Ubuntu20.04 1.開啟mysql服務 sytemctl start mysql不然,命令行進入myql交互行提交命令后,就會出現4200錯誤。 2.顯示所有數據庫 SHOW DATABASES;注意復數s,畢竟很多數據庫 3.新建數據庫test CREATE DATABASE …

【學習筆記】計算機組成原理(九+十)

控制單元的功能 文章目錄 控制單元的功能9.1 微操作命令的分析9.1.1 取指周期9.1.2 間址周期9.1.3 執行周期9.1.4 中斷周期 9.2 控制單元的功能9.2.1 控制單元的外特性9.2.2 控制信號舉例9.2.3 多級時序系統9.2.4 控制方式 控制單元的設計10.1 組合邏輯設計10.1.1 組合邏輯控制…

LabVIEW與Simulink的通信及調用方式

LabVIEW和Simulink可以通過多種方式進行通信和集成,實現數據交互和功能調用。常見的通信方式包括TCP/IP、UDP、共享內存等,此外還可以利用MATLAB Script Node和S-Function等直接調用對方的功能。這些方法使得LabVIEW和Simulink能夠協同工作,充…

[Algorithm][動態規劃][子序列問題][最長遞增子序列的個數][最長數對鏈]詳細講解

目錄 1.最長遞增子序列的個數1.題目鏈接2.算法原理詳解3.代碼實現 2.最長數對鏈1.題目鏈接2.算法原理詳解3.代碼實現 1.最長遞增子序列的個數 1.題目鏈接 最長遞增子序列的個數 2.算法原理詳解 注意:本題思路和思維方式及用到的方法很值得考究,個人感…

dubbo復習:(18)服務端Filter

用來在服務響應返回到客戶端之前進行額外處理。 一、定義Filter package cn.edu.tju.config;import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invocation; import org.apache.du…

大量path計算優化方案

1.影響path基礎屬性數據做key緩存,緩存的path應去除坐標變換,歸一化。基礎屬性應滿足CAB, BC-A 2.高頻path操作以(keykey操作)做新key緩存。 3.高頻修改高級屬性,以新key屬性變更做新key緩存。 4.key與id做中轉映射&am…

redis修改密碼

基于鏡像部署 其實在dockerhub上都有寫 redsi 配置文件從哪找呢? 答案是:從官網或者從github上的release里找到你需要的對應版本解壓后有配置文件 配置文件路徑在哪呢 用redis-server /etc/redis/redis.conf 去指定啟動使用的配置文件 好那么接下來就是一些簡單的…

ad18學習筆記20:焊盤設置Solder Mask Expansion(阻焊層延伸)

【AD18新手入門】從零開始制造自己的PCB_ad18教程-CSDN博客 Altium Designer繪制焊盤孔(Pad孔)封裝庫的技巧,包括原理圖封裝和PCB封裝_嗶哩嗶哩_bilibili 默認的焊盤中間是有個過孔的,單層焊盤(表貼燭盤)…

工作流 Activiti7 初始

文章目錄 ??1.1 Activiti 介紹??1.2 Activiti 開發流程??1.3 BPMN 2.0 規范是什么??1.4 BPMN 2.0 基本流程符號????1.4.1 事件 Event????1.4.2 活動????1.4.3 網關 Gateway ??1.5 Activiti API 服務接口????1.5.1 核心Service接口及其獲取 ??1.1 A…

AI科普:TensorFlow 的基本概念和使用場景

TensorFlow是一個開源的深度學習框架,由Google開發并于2015年發布。它提供了一個使用數據流圖進行數值計算的接口,可以在不同的硬件平臺上運行,包括CPU、GPU和TPU。 TensorFlow的核心概念是張量(Tensor)和計算圖&…

fps游戲如何快速定位矩陣

fps游戲如何快速定位矩陣 矩陣特點: 1、第一行第一列值的范圍在**-1 ---- 1**之間&#xff0c;如果開鏡之后值會變大。 2、第一行第三列的值始終為 0。 3、第一行第四列 的值比較大 &#xff0c; >300或者**<-300**。 根據這三個特點&#xff0c;定位矩陣已經足夠了…

centos7.9離線安裝mysql5.7

centos7.9離線安裝mysql5.7 查詢mysql查詢組查詢用戶不存在創建即可&#xff0c;創建mysql用戶組上傳下載的安裝包創建my.cnf文件修改配置文件修改mysql登陸密碼 centos7.9 mysql5.7 查詢mysql rpm -qa | grep mysql我這里查詢是不存在&#xff0c;如果你的存在可以用rm -rf […

11- Redis 中的 SDS 數據結構

字符串在 Redis 中是很常用的&#xff0c;鍵值對中的鍵是字符串類型&#xff0c;值有時也是字符串類型。 Redis 是用 C 語言實現的&#xff0c;但是它沒有直接使用 C 語言的 char* 字符數組來實現字符串&#xff0c;而是自己封裝了一個名為簡單動態字符串&#xff08;simple d…

ubuntu22 部署zookeeper + kafka集群 配置開機自啟動

ufw disabled #關閉防火墻 或者 放開指定端口 vim /etc/hosts #配置ip host映射關系 10.3.1.96 node1 10.3.1.97 node2 #1.所有機器安裝jdk apt install openjdk-8-jdk -y java -version #export JAVA_HOME/usr/lib/jvm/jdk1.8.0_202 #2.部署zookeeper集群 cd /usr…

【spring】Spring Boot3.3.0發布啦

spring最新版本 springboot官網&#xff1a;Spring Boot :: Spring Boot Spring Boot 3.3 發行說明&#xff1a;https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.3-Release-Notes 開發環境的要求對比表 Spring BootJDKSpringMavenGradle3.3.017 ~ 226.1…

Mac電腦pd虛擬機專用windows系統鏡像(m1/intel)win10、11鏡像文件

入手了Mac電腦后&#xff0c;由于需要用到Windows軟件&#xff0c;又嫌安裝雙系統太復雜&#xff0c;這時候Mac就用到了安裝虛擬機&#xff0c;目前最好用的虛擬機是Parallels Desktop&#xff0c;win鏡像版本要根據自己的喜好選對&#xff0c;在此提供分別兼容M1和Intel的win1…