設計模式--建造者模式詳解

建造者模式

  • 建造者模式也屬于創建型模式,它提供了一種創建對象的最佳方式

  • 定義:將一個復雜對象的構建和它的表示分離,使得同樣的構建過程可以創建不同的表示(假設有不同的建造者實現類,可以產生不同的產品)

  • 主要作用:在用戶不知道對象的創建過程和細節的情況下(用戶只需要調指揮者來創建就可以了)就可以直接創建復雜的對象

  • 用戶只需要給出指定復雜對象的類型和內容,建造者負責按順序創建復雜對象(把內部的建造過程和細節隱藏起來)

  • 例子:

    • 工廠(建造者模式):負責制造汽車(組裝過程和細節在工廠內)

    • 汽車購買者(用戶):你只要說出你需要的型號(對象的類型與內容),然后可以直接購買就可以使用了(雖然不知道汽車怎么組裝的(車輪、車門、發動機、方向盤等等))

  • 角色分析:

  • 既然是建造者模式,那么我們還是繼續就以造房子為例子,假設將造房簡化為以下步驟:

    • 地基

    • 鋼筋工程

    • 鋪電線

    • 粉刷

如果要蓋一間房子,首先是要一個建筑公司或工程承包商(指揮者),承包商指揮工人(具體建造者)來造房子(產品),最后驗收

代碼展示:

首先先創建抽象建造者

package com.lyc.builder.demo01;
//抽象的建造者,只負責定義一些接口與方法
public abstract class Builder {public abstract void buildPartA();public abstract void buildPartB();public abstract void buildPartC();public abstract void buildPartD();//完工:得到產品public abstract Product getResult();
}

再創建產品類

package com.lyc.builder.demo01;import lombok.Data;//產品:房子
@Data
public class Product {private String partA;private String partB;private String partC;private String partD;
}

再創建具體建造者實現類

package com.lyc.builder.demo01;
//具體的建造者 worker是builder的具體實現,一個builder可能有幾個不同的worker
public class Worker extends Builder{private Product product;public Worker(){product = new Product();}@Overridepublic void buildPartA() {product.setPartA("partA");System.out.println("partA");}@Overridepublic void buildPartB() {product.setPartB("partB");System.out.println("partB");}@Overridepublic void buildPartC() {product.setPartC("partC");System.out.println("partC");}@Overridepublic void buildPartD() {product.setPartD("partD");System.out.println("partD");}@Overridepublic Product getResult() {return product;}
}

在創建指揮類Director

package com.lyc.builder.demo01;
//指揮者 核心,負責指揮構建一個工程,工程如何構建,有他決定
public class Director {//指揮工人按照順序建造房子public Product builder(Builder builder){//指揮者可以指揮工人按照不同的順序執行方法,builder.buildPartA();builder.buildPartB();builder.buildPartC();builder.buildPartD();//返回產品return builder.getResult();}
}

最后進行測試

public class Test {public static void main(String[] args) {//指揮Director director = new Director();Product builder = director.builder(new Worker());System.out.println(builder.toString());}
}

細節分析:

  • 上面示例是Builder模式的常規用法,導演Director在Builder模式中具有重要的作用,它用于指導具體構建者如何構建產品控制調用先后次序并向調用者返回完整的產品類,但是有些情況下需要簡化系統結構,可以把Director與抽象建造者進行結合

  • 通過靜態內部類方式實現零件無序裝配構造,這種方式使用更加靈活,更符合定義,內部有復雜對象的默認實現,使用時可以根據用戶需求自由定義更改內容,并且無需改變具體的構造方式。就可以生產出不同復雜的產品

  • 比如:漢堡套餐,服務員(具體建造者)可以隨意搭配任意幾種產品組成一款套餐(產品),比第一種少了Director,主要是因為第二種方式把指揮者交給用戶操作,使得產品創建更加簡單靈活

第二種方式代碼展示:

首先還是需要創建抽象建造類

public abstract class Builder {public abstract Builder buildPartA(String msg); //漢堡public abstract Builder buildPartB(String msg); //可樂public abstract Builder buildPartC(String msg); //薯條public abstract Builder buildPartD(String msg); //甜品// 返回產品public abstract Product getResult();
}

創建產品類(這里存放著默認的產品)

import lombok.Data;//產品:套餐
@Data
public class Product {//默認套餐private String partA = "漢堡";private String partB = "可樂";private String partC = "薯條";private String partD = "甜點";
}

具體的創建者實現類

package com.lyc.builder.demo02;
//具體建造者
public class Worker extends Builder{private Product product;public Worker(){product = new Product();}@Overridepublic Builder buildPartA(String msg) {product.setPartA(msg);return this;}@Overridepublic Builder buildPartB(String msg) {product.setPartB(msg);return this;}@Overridepublic Builder buildPartC(String msg) {product.setPartC(msg);return this;}@Overridepublic Builder buildPartD(String msg) {product.setPartD(msg);return this;}@Overridepublic Product getResult() {return product;}
}

最后進行測試

package com.lyc.builder.demo02;public class Test {public static void main(String[] args) {//服務員Worker worker = new Worker();//鏈式編程 :在原來的基礎上,可以自由組合,如果不組合,也有默認的套餐Product result = worker.buildPartA("全家桶").buildPartB("雪碧").getResult();System.out.println(result.toString());}
}

這里將指揮者與客戶端相結合,讓客戶端自己來進行套餐的搭配。

建造者模式與工廠模式的區別:

工廠模式是造什么,建造者模式是怎么造,一個宏觀,一個微觀

建造者模式優點:

  • 產品的建造與表示分離,實現了解耦,使用建造者模式可以使客戶端不必知道產品內部組成的細節。

  • 將復雜的產品的創建步驟分解在不同的方法中,使得創建過程更加清晰

  • 具體的建造者類之間是相互獨立的,這有利于系統的擴展,增加新的具體建造者無需修改原有類庫的代碼,符合“開閉原則”。

缺點:

  • 建造者模式所創建的產品一般具有較多的共同點,其組成部分相似;如果產品之間的差異性很大,則不適合使用創造者模式,因此其適用范圍受到了一定的限制。

  • 如果產品的內部變化復雜,可能會導致需要定義很多具體建造者來實現這種變化,導致系統變得很龐大

應用場景:

  • 需要生成的產品對象有復雜的內部結構,這些產品對象具備共性;

  • 隔離復雜對象的創建和使用,并使得相同的創建過程可以創建不同的產品。

  • 適合于一個具有較多的零件(屬性)的產品(對象)的創建過程。

建造者與抽象工廠模式的比較:

  • 與抽象工廠模式相比,建造者模式返回一個組裝好的完整產品,而抽象工廠模式返回一系列相關的產品,這些產品位于不同的產品等級結構,構成了一個產品族

  • 在抽象工廠模式中,客戶端實例化工廠類,然后調用工廠方法獲取所需產品對象,抽象工廠模式側重于直接通過工廠制造獲得對象 而在建造者模式中客戶端可以不直接調用建造者的相關方法,而是通過指揮者類來指導如何生成對象,包括對象的組裝過程和建造步驟,它側重于一步步構造一個復雜對象,返回一個完整的對象。

  • 如果將抽象工廠模式看成汽車配件生產工廠,生產一個產品族的產品,那么建造者模式就是一個汽車組裝工廠,通過對部件的組裝可以返回一輛完整的汽車!

我們需要清楚的認識到工廠模式與創建者模式的區別,并且勤加練習,希望對大家有所幫助

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

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

相關文章

PCB 過孔銅厚的深入指南

***前言:在上一期的文章中介紹了PCB制造的工藝流程,但仍然想在過孔的銅厚和PCB的過孔厚徑比兩個方面再深入介紹。 PCB銅厚的定義 電路中銅的厚度以盎司(oz)**表示。那么,為什么用重量單位來表示厚度呢? 盎司(oz)的定義 將1盎司(28.35 克)的銅…

如何配置 Conda 使用鏡像源加速

如何配置 Conda 使用鏡像源加速 為了提高使用 Anaconda 或 Miniconda 時包管理的速度,特別是在國內網絡環境下,可以通過配置鏡像源來實現更快的下載。以下是詳細的步驟說明: 1. 安裝 Conda(如果尚未安裝) 如果你還沒…

【k8s】k8s是怎么實現自動擴縮的

Kubernetes 提供了多種自動擴縮容機制,主要包括 Pod 水平自動擴縮(HPA)、垂直 Pod 自動擴縮(VPA) 和 集群自動擴縮(Cluster Autoscaler)。以下是它們的實現原理和配置方法: 1. Pod …

Reflex 完全指南:用 Python 構建現代 Web 應用的終極體驗

“寫 Python,就能構建 Web 前端。”——這不再是夢想,而是由 Reflex 帶來的現實。 過去,構建一個現代 Web 應用意味著你要學會前端(React/JS/HTML/CSS) 后端(Flask/Django) API 交互&#xff08…

Vue實戰(08)解決 Vue 項目中路徑別名 `@` 在 IDE 中報錯無法識別的問題

一、引言 ? 在 Vue 項目開發過程中,路徑別名是一個非常實用的特性,它能夠幫助開發者簡化文件引用路徑,提高代碼的可讀性和可維護性。其中, 作為一個常見的路徑別名,通常被用來指向項目的 src 目錄。然而,…

5.學習筆記-SpringMVC(P61-P70)

SpringMVC-SSM整合-接口測試 (1)業務層接口使用junit接口做測試 (2)表現層用postman做接口測試 (3)事務處理— 1)在SpringConfig.java,開啟注解,是事務驅動 2)配置事務管理器(因為事務管理器是要配置數據源對象&…

[論文閱讀]REPLUG: Retrieval-Augmented Black-Box Language Models

REPLUG: Retrieval-Augmented Black-Box Language Models REPLUG: Retrieval-Augmented Black-Box Language Models - ACL Anthology NAACL-HLT 2024 在這項工作中,我們介紹了RePlug(Retrieve and Plug),這是一個新的檢索增強型…

Mysql的深度分頁查詢優化

一、深度分頁為什么慢? 當執行 SELECT * FROM orders ORDER BY id LIMIT 1000000, 10 時: MySQL 會掃描前 1,000,010 行,丟棄前 100 萬行,僅返回 10 行。偏移量(offset)越大,掃描行數越多&…

最新扣子(Coze)案例教程:Excel數據生成統計圖表,自動清洗數據+轉換可視化圖表+零代碼,完全免費教程

大家好,我是斜杠君。 知識星球群有同學和我說每天的工作涉及很多數據表的重復操作,想學習Excel數據表通過大模型自動轉數據圖片的功能。 今天斜杠君就帶大家一起搭建一個智能體,以一個銷售行業數據為例,可以快速實現自動清洗Exc…

Uniapp 中緩存操作指南

在 Uniapp 中,你可以使用三種方式操作緩存:同步方法、異步方法和 Vuex 持久化存儲。以下是詳細的設置、獲取和清除緩存的方法: 1. 同步方法 設置緩存 uni.setStorageSync(key, value); // 示例 uni.setStorageSync(token, abc123); 獲取緩存 const value = uni.getStor…

k8s的yaml文件里的volume跟volumeMount的區別

volume 是 Pod 級別的資源,用于定義存儲卷。它是一個獨立于容器的存儲資源,可以被一個或多個容器共享使用。volume 的定義位于 Pod 的 spec.volumes 部分。 特點 獨立性:volume 是 Pod 的一部分,而不是容器的一部分。它獨立于容…

梅毒單陽能否通過國企體檢?

國企體檢通常會參照公務員體檢標準進行,梅毒檢測是其中的常規項目。 一、明確“梅毒單陽”的定義 檢測指標解析 TPPA陽性RPR陰性:可能為既往感染已治愈,或極早期/晚期梅毒; RPR陽性TPPA陰性:需警惕假陽性&#xff08…

Python 爬蟲實戰 | 企名科技

文章目錄 一、企名科技1、目標網站2、網站特點3、確定解密位置4、扣js代碼 一、企名科技 1、目標網站 網址:https://wx.qmpsee.com/articleDetail?idfeef62bfdac45a94b9cd89aed5c235be目標數據:獲取消費行業研究下面的13篇文章數據 2、網站特點 服…

Pikachu靶場

本質是信任了不可信的客戶端輸入。防御核心: 永不信任客戶端提交的權限參數(如 user_id, role)。強制服務端校驗用戶身份與操作權限。定期審計權限模型,避免業務迭代引入新漏洞。 水平越權 1,按照網站的提示要求登錄 進…

C++區別于C語言的提升用法(萬字總結)

1.namespace產生原因 在C語言中,變量,函數,以至于類都是大量存在的,因此會產生大量的名稱存在于全局作用域中,可能產生很多沖突,至此c的祖師爺為避免命名沖突和名字的污染,造出來了關鍵字names…

數據庫day-07

一、實驗名稱和性質 子查詢 驗證 設計 二、實驗目的 1.掌握子查詢的嵌套查詢; 2.掌握集合操作 3.了解EXISTS嵌套查詢方法; 三、實驗的軟硬件環境要求 硬件環境要求: PC機(單機) 使用的軟件名稱、版本號以及模塊…

【前端】【業務場景】【面試】在前端開發中,如何實現文件的上傳與下載功能,并且處理可能出現的錯誤情況?

前端文件上傳與下載攻略 本文目標&#xff1a;幫你快速掌握文件上傳 & 下載的核心實現方式&#xff0c;并在常見出錯場景下保持“優雅不崩潰”。 一、文件上傳 1. 基礎結構 <input type"file" id"fileInput" /> <button id"uploadBtn&…

Kafka 消息積壓監控和報警配置的詳細步驟

Kafka 消息積壓監控和報警配置的詳細步驟示例&#xff0c;涵蓋常用工具&#xff08;如 Prometheus Grafana、云服務監控&#xff09;和自定義腳本方法&#xff1a; 一、監控配置 方法1&#xff1a;使用 Prometheus Grafana kafka-exporter 步驟1&#xff1a;部署 kafka-ex…

【C++】內存管理:內存劃分、動態內存管理(new、delete用法)

文章目錄 一、C/C中的內存劃分二、C語言中動態內存管理方式三、C中動態內存管理方式1、new、delete基本用法(1)、內置類型(2)、自定義類型 2、operator new與operator delete函數3、new和delete的實現原理&#xff08;1&#xff09;內置類型&#xff08;2&#xff09;自定義類型…

C# 實戰_RichTextBox選中某一行條目高亮,離開恢復

C# 中控件richtextbox中某一行的條目內容高亮&#xff0c;未選中保持不變。當鼠標點擊某一行的條目高亮&#xff0c;離開該條目就恢復默認顏色。 運行效果&#xff1a; 核心代碼實現功能&#xff1a; //高亮指定行的方法private void HighlightLine(RichTextBox rtb,int lineI…