設計模式(四)創建型:生成器模式詳解

設計模式(四)創建型:生成器模式詳解

生成器模式(Builder Pattern)是 GoF 23 種設計模式中的核心創建型模式之一,其核心價值在于將一個復雜對象的構建過程與其表示分離,使得同樣的構建過程可以創建不同的表示。它特別適用于構造過程穩定但組成部分多變、配置參數繁雜的對象,如配置文件解析器、SQL 查詢構造器、HTML 文檔生成器、API 請求對象等。生成器模式通過分步構建對象并支持方法鏈式調用(Fluent Interface),極大提升了代碼的可讀性與可維護性。在現代框架中,該模式已演變為“流式 API”設計的基礎,是構建復雜對象的優雅解決方案。

一、生成器模式詳細介紹

生成器模式解決的是“復雜對象構造”中的常見痛點:當一個類的構造函數參數過多(尤其是存在大量可選參數)時,直接使用構造器或 setter 方法會導致代碼冗長、易錯且難以閱讀。生成器模式通過引入一個獨立的“生成器”對象,將對象的構建過程分解為多個清晰的步驟,最終通過 build() 方法一次性完成對象的創建。

該模式涉及以下關鍵角色:

  • Product(產品類):表示被構建的復雜對象。它通常具有多個組成部分或配置項,且構造過程較為復雜。該類的構造函數通常是私有的,防止外部直接實例化。
  • Builder(抽象生成器接口或抽象類):聲明構建 Product 所需的各個構建步驟(如 setPartA()setPartB()),以及一個返回最終產品對象的 build() 方法。它定義了構建過程的契約。
  • ConcreteBuilder(具體生成器):實現 Builder 接口,負責具體地執行每一步構建操作,并維護一個 Product 實例的引用。它可以根據需要提供不同的構建邏輯,從而生成不同配置的 Product。
  • Director(指揮者,可選):負責調用 Builder 對象的各個構建方法,按照特定順序執行構建流程。在許多現代實現中,Director 的職責被客戶端直接承擔,通過鏈式調用完成構建。

生成器模式的核心優勢在于:

  • 解耦構建過程與表示:構建邏輯集中在 Builder 中,Product 類無需關心如何被創建。
  • 支持分步構建:允許逐步設置對象的各個部分,尤其適合依賴外部數據或條件判斷的場景。
  • 實現不可變對象:Product 可以在構建完成后設為不可變(Immutable),提升線程安全性。
  • 支持方法鏈式調用:每個構建方法返回 this,實現流暢的 API 風格(Fluent API),如 builder.setA("a").setB("b").build()

與“工廠模式”相比,生成器更關注“如何構建”一個對象,而工廠關注“創建哪一個”對象。生成器適用于構建過程復雜、參數多變的場景,而工廠適用于類型選擇明確的場景。

二、生成器模式的UML表示

以下是生成器模式的標準 UML 類圖:

implements
creates
uses
constructed by
Product
-partA: String
-partB: int
-partC: boolean
+getPartA()
+getPartB()
+getPartC()
-Product(builder: Builder)
?abstract?
Builder
+setPartA(partA: String)
+setPartB(partB: int)
+setPartC(partC: boolean)
+build()
ConcreteBuilder
-partA: String
-partB: int
-partC: boolean
+setPartA(partA: String)
+setPartB(partB: int)
+setPartC(partC: boolean)
+build()
Director
-builder: Builder
+constructMinimal()
+constructFull()

圖解說明

  • Product 是最終要構建的復雜對象,其構造函數為私有,只能通過 Builder 創建。
  • Builder 是抽象生成器,定義了設置各個部分的方法和 build() 方法。
  • ConcreteBuilder 實現 Builder,維護構建過程中的中間狀態,并在 build() 中使用這些狀態創建 Product
  • Director(可選)封裝了標準的構建流程,如“最小構建”或“完整構建”。
  • 客戶端可通過 ConcreteBuilder 鏈式調用設置參數,最后調用 build() 獲取最終對象。

三、一個簡單的Java程序實例

以下是一個基于生成器模式的 Java 示例,模擬構建一個 Email 對象:

// 產品類:Email
final class Email {private final String from;private final String to;private final String subject;private final String body;private final boolean isHtml;private final boolean isPriority;// 私有構造函數,只能通過 Builder 創建private Email(Builder builder) {this.from = builder.from;this.to = builder.to;this.subject = builder.subject;this.body = builder.body;this.isHtml = builder.isHtml;this.isPriority = builder.isPriority;}// Getter 方法public String getFrom() { return from; }public String getTo() { return to; }public String getSubject() { return subject; }public String getBody() { return body; }public boolean isHtml() { return isHtml; }public boolean isPriority() { return isPriority; }@Overridepublic String toString() {return "Email{" +"from='" + from + '\'' +", to='" + to + '\'' +", subject='" + subject + '\'' +", body='" + body + '\'' +", isHtml=" + isHtml +", isPriority=" + isPriority +'}';}// 靜態內部生成器類public static class Builder {private String from;private String to;private String subject;private String body;private boolean isHtml = false;private boolean isPriority = false;public Builder from(String from) {this.from = from;return this; // 支持鏈式調用}public Builder to(String to) {this.to = to;return this;}public Builder subject(String subject) {this.subject = subject;return this;}public Builder body(String body) {this.body = body;return this;}public Builder html(boolean html) {this.isHtml = html;return this;}public Builder priority(boolean priority) {this.isPriority = priority;return this;}// 構建最終對象public Email build() {// 可在此處添加參數校驗if (from == null || to == null || subject == null || body == null) {throw new IllegalStateException("Required fields (from, to, subject, body) must be set.");}return new Email(this);}}
}// 客戶端使用示例
public class BuilderPatternDemo {public static void main(String[] args) {// 使用生成器構建一個普通郵件Email email1 = new Email.Builder().from("alice@example.com").to("bob@example.com").subject("Hello").body("This is a plain text email.").html(false).priority(false).build();System.out.println(email1);// 使用生成器構建一個高優先級 HTML 郵件Email email2 = new Email.Builder().from("admin@system.com").to("user@company.com").subject("Urgent: System Alert").body("<h1>CRITICAL ALERT!</h1><p>Server is down.</p>").html(true).priority(true).build();System.out.println(email2);}
}

運行說明

  • Email 類是不可變的,所有字段在構建后不可更改。
  • Builder 類提供鏈式方法設置各個字段,最后調用 build() 創建 Email 實例。
  • 客戶端代碼清晰、易讀,避免了長參數列表或 setter 的繁瑣調用。
  • build() 方法中可加入參數校驗,確保對象的完整性。

四、總結

生成器模式通過引入獨立的構建過程,成功解決了復雜對象構造的難題:

  • 提升可讀性:鏈式調用使代碼像自然語言一樣流暢。
  • 支持可選參數:無需為不同參數組合定義多個構造函數(避免“伸縮構造器反模式”)。
  • 保證對象完整性:可在 build() 階段集中校驗參數,防止創建不合法對象。
  • 支持不可變性:Product 可設計為不可變對象,增強線程安全。

但也存在缺點:

  • 增加類復雜度:需要為每個復雜類定義一個 Builder。
  • 不適合簡單對象:對于字段少、構造簡單的類,使用 Builder 反而增加冗余。

因此,應在“對象復雜度”與“代碼簡潔性”之間權衡使用。

架構師洞見:
生成器模式是現代 API 設計的“黃金標準”。在 Spring、OkHttp、JPA Criteria API 等主流框架中,流式構建(Fluent Builder)已成為標配。架構師應認識到:生成器不僅是創建對象的工具,更是一種提升開發者體驗(DX)的設計哲學。它通過“意圖清晰的 API”降低使用門檻,減少錯誤。未來,隨著 DSL(領域特定語言)和代碼生成技術的發展,生成器將進一步自動化——通過注解處理器或 APT 自動生成 Builder 代碼,消除樣板代碼。掌握生成器模式,有助于設計出既強大又易用的內部組件與公共 API,是構建高質量、可維護系統的關鍵能力。在微服務配置、消息構造、查詢構建等高頻場景中,生成器模式的價值尤為突出。

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

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

相關文章

《Angular+Spring Boot:ERP前端采購銷售庫存協同架構解析》

基于Angular與Spring Boot構建的全棧ERP前端&#xff0c;絕非技術的簡單疊加&#xff0c;而是通過深度融合兩者特性&#xff0c;打造出兼具穩定性與靈活性的業務載體。Angular的組件化架構將復雜界面拆解為可復用的獨立單元&#xff0c;依賴注入機制則讓服務調用與數據流轉條理…

Java 排序

文章目錄排序插入排序分析希爾排序分析選擇排序分析堆排序分析冒泡排序分析快速排序霍爾法分析挖坑法找基準前后指針法題目快排的優化三數取中法非遞歸實現快排歸并排序分析非遞歸實現歸并排序海量數據的排序非比較的排序計數排序分析基數排序桶排序排序 穩定的排序&#xff1…

日本IT就職面試|儀容禮儀篇分享建議

日系企業で好印象を與える「身だしなみ」と「面接マナー」ガイドこんにちは。 日系企業への就職?転職活動をされている方にとって、「第一印象」は合否を左右する大切なポイントですよね。実は、面接の評価は入室の瞬間から始まっていると言っても過言ではありません。 今回は…

英語聽力口語詞匯-8.美食類

1.crispy,crisp adj.酥脆的&#xff0c;易碎的 2.sweet adj.甜的 比如說chocolate is so sweet and delicious 3.chewy adj.難嚼的&#xff0c;難咽的 4.oatmeal n.燕麥粉 5.pickle n.泡菜 7.stir-fry v.炒菜 8.bacon n.咸肉&#xff0c;熏肉 9.yummy adj.美味可口的 1…

力扣7:整數反轉

力扣7:整數反轉題目思路代碼題目 給你一個 32 位的有符號整數 x &#xff0c;返回將 x 中的數字部分反轉后的結果。 如果反轉后整數超過 32 位的有符號整數的范圍 [?2^31, 2^31 ? 1] &#xff0c;就返回 0。 思路 這道題我們可以分成兩部分來做&#xff0c;一是完成反轉二…

PWM信號控制電機

1&#xff1a;環境 STM32F103C8T6 KEIL5.38 2個電機 2個輪子 1個L298N STLINKV2 CH340 1個4位獨立按鍵 杜邦線若干 2&#xff1a;代碼 key.h #ifndef __KEY_H #define __KEY_H#include "stm32f10x.h"extern volatile uint8_t key_t ; extern volatile uint8_t …

開源賦能產業,生態共筑未來 | 開源科學計算與系統建模(openSCS)分論壇圓滿舉行

2025開放原子開源生態大會于7月23日-24日在北京國家會議中心召開。本屆大會以“開源賦能產業&#xff0c;生態共筑未來”為主題&#xff0c;匯聚政、產、學、研、用、金、創、投等各領域開源力量&#xff0c;聚焦開源政策導向、生態發展趨勢、開源產業實踐&#xff0c;共探中國…

Android廣播機制體系初識

Android廣播機制體系大白話把Android的廣播機制想象成小區里的“大喇叭”誰在喊話&#xff1f;任何App或系統都能當“大喇叭”&#xff0c;比如喊一嗓子“電量不足啦&#xff01;”&#xff08;這就是發送廣播&#xff09;誰在聽&#xff1f;其他App只要“豎起耳朵”&#xff0…

微信小程序點擊輸入框時,頂部導航欄被遮擋問題如何解決?

前言 不知道大家開發微信小程序的時候有沒有遇到這么一個問題&#xff0c;就是在表單頁面中&#xff0c;點擊輸入框后&#xff0c;輸入框頂起會把頂部欄給遮擋住&#xff0c;如下圖所示&#xff1a;遇到這種情況有沒有解決的辦法呢&#xff1f;能不能既將頁面頂起&#xff0c;同…

通過具有一致性嵌入的大語言模型(LMMs)實現端到端乳腺癌放射治療計劃制定|文獻速遞-醫學影像算法文獻分享

Title題目End-to-end breast cancer radiotherapy planning via LMMs with consistencyembedding通過具有一致性嵌入的大語言模型&#xff08;LMMs&#xff09;實現端到端乳腺癌放射治療計劃制定01文獻速遞介紹近年來&#xff0c;受大型語言模型&#xff08;LLM&#xff09;啟發…

vscode npm run build打包報ELIFECYCLE

npm run build打包報ELIFECYCLE 是內存溢出解決方案&#xff1a;修改build腳本 &#xff1a;"build": "node --max_old_space_size4096 node_modules/vue/cli-service/bin/vue-cli-service.js build",

【lucene】BlockMaxConjunctionScore

BlockMaxConjunctionScorer 是 Lucene 8.5 引入的一個高性能交集打分器&#xff08;conjunction scorer&#xff09;&#xff0c;專門用于處理 多條件“與”查詢&#xff08;AND 查詢&#xff09; 的場景。它基于 Block-Max WAND&#xff08;BMW&#xff09;算法&#xff0c;可…

Androidstudio 上傳當前module 或本地jar包到maven服務器。

1.設置gradle版本到8.0 gradle-wrapper.properties文件中設置&#xff1a; distributionUrlhttps\://mirrors.aliyun.com/macports/distfiles/gradle/gradle-8.0-bin.zip 2.設置項目根目錄build.gradle 設置agp版本和maven插件版本&#xff08;和gralde版本有對應關系&#xff…

Python動態規劃:從基礎到高階優化的全面指南

動態規劃&#xff08;Dynamic Programming&#xff09;是解決復雜優化問題的核心技術&#xff0c;也是算法領域的明珠。本文將深入探討Python實現動態規劃的全方位技術&#xff0c;涵蓋基礎概念、經典問題、優化技巧和實際工程應用&#xff0c;帶您掌握這一強大工具的精髓。一、…

視覺大模型部署實踐篇(Docker+dify+ollama安裝)

一、概述 目的:實現一個本地化部署的大模型,通過工作流對圖像進行一些處理。基于此,我選擇了Docker+Dify+Ollama的部署。 具體實現邏輯:Docker來運行dify,dify用來繪制大模型的工作流或者rag等,Ollama用來部署本地大模型,dify調用Ollama部署的大模型進行推理。 二、Dock…

服務器啟動日志等級

目錄 標準日志等級 服務器啟動階段常見日志 日志配置建議 常見服務器/工具的日志等級配置方式 ET框架 Apache/Nginx 等 Web 服務器 Docker 容器 服務器啟動過程中的日志等級是幫助開發者和運維人員理解系統狀態的重要工具。常見的日志等級及其含義如下&#xff1a; 標準…

linux_centos7安裝jdk8_采用jdk安裝包安裝

你問我為什么不用yum? 我yum安裝不了&#xff0c;我也解決不了qwq. 文章目錄一.下載安裝包1.找到安裝包下載位置2.上傳安裝包到linux3.解壓jdk安裝包4.配置環境一.下載安裝包 1.找到安裝包下載位置 去官網找到你要下載jdk版本&#xff1a; Oracle官網 下面演示安裝jdk8的&am…

Linux驅動23 --- RkMedia 使用

目錄 一、上電自動掛載 二、RkMedia 2.1 認識 RkMedia rtsp rtmp RTSP 和 RTMP 的選擇 2.2 安裝 VLC 2.2 RkMedia 例程使用 一、上電自動掛載 cd /etc/init.d/ vi Smyprofile.sh 添加這個內容 #!/bin/sh ifconfig eth0 192.168.66.88 mount -t nfs 192.168.66.66…

Linux:線程同步與線程互斥

線程互斥競態條件當多個線程&#xff08;或進程&#xff09;并發訪問和操作同一個共享資源&#xff08;如變量、文件、數據庫記錄等&#xff09;時&#xff0c;最終的結果依賴于這些線程執行的相對時序&#xff08;即誰在什么時候執行了哪條指令&#xff09;。 由于操作系統調度…

HTML 常用標簽速查表

HTML 常用標簽速查表 &#x1f9f1; 結構類標簽 標簽含義用途說明<html>HTML文檔根元素所有HTML內容的根節點<head>頭部信息放置元信息&#xff0c;如標題、引入CSS/JS等<body>頁面內容主體所有可視內容的容器&#x1f4dd; 文本與標題標簽 標簽含義用途說…