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

建造者模式(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、關于建造者模式與工廠模式區別

  1. 工廠模式,一般都是創建一個產品,注重的是把這個產品創建出來就行,只要創建出來,不關心這個產品的組成部分。從代碼上看,工廠模式就是一個方法,用這個方法就能生產出產品。,,
  2. 建造者模式,也是創建一個產品,但是不僅要把這個產品創建出來,還要關系這個產品的組成細節,組成過程。 從代碼上看,建造者模式在建造產品時,這個產品有很多方法,建造者模式會根據這些相同方法但是不同執行順序建造出不同組成細節的產品。

二、建造者模式 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);}
}

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

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

相關文章

圖文并茂 VLAN 詳解,讓你看一遍就理解 VLAN

一、為什么需要VLAN 1.1、什么是VLAN? VLAN(Virtual LAN),翻譯成中文是“虛擬局域網”。LAN可以是由少數幾臺家用計算機構成的網絡,也可以是數以百計的計算機構成的企業網絡。VLAN所指的LAN特指使用路由器分割的網絡——也就是廣播域。 在此讓我們先復習…

認識VLAN,并學會VLAN的劃分和網絡配置實例

VLAN的劃分和網絡的配置實例 1、VLAN基礎知識 VLAN(Virtual Local Area Network)的中文名為:“虛擬局域網”,注意和VPN(虛擬專用網)進行區分。 VLAN是一種將局域網設備從邏輯上劃分(不是從物…

VLAN劃分及配置注意事項

VLAN(Virtual Local Area Network)即虛擬局域網,是將一個物理的LAN在邏輯上劃分成多個廣播域的通信技術。VLAN內的主機間可以直接通信,而VLAN間不能直接通信,從而將廣播報文限制在一個VLAN內。VLAN之間的通信是通過第3…

Docker原理剖析

一、簡介 1、了解Docker的前生LXC LXC為Linux Container的簡寫。可以提供輕量級的虛擬化,以便隔離進程和資源,而且不需要提供指令解釋機制以及全虛擬化的其他復雜性。相當于C中的NameSpace。容器有效地將由單個操作系統管理的資源劃分到孤立的組中&#…

獲取Linux內存、cpu、磁盤IO等信息

#!/bin/bash # 獲取要監控的本地服務器IP地址 IPifconfig | grep inet | grep -vE inet6|127.0.0.1 | awk {print $2} echo "IP地址:"$IP# 獲取cpu總核數 cpu_numgrep -c "model name" /proc/cpuinfo echo "cpu總核數:"$c…

Docker容器網絡解析

Docker 容器網絡的發展歷史 在 Dokcer 發布之初,Docker 是將網絡、管理、安全等集成在一起的,其中網絡模塊可以為容器提供橋接網絡、主機網絡等簡單的網絡功能。 從 1.7 版本開始,Docker正是把網絡和存儲這兩部分的功能都以插件化形式剝離出來…

將指定excel的一列數據提取到另一個excel的指定列

#!/usr/bin/env python import openpyxl bjD:/地市縣公司/西藏臺賬數據分析-設備臺帳分析.xlsx wb openpyxl.load_workbook (bj) get_sheets wb.sheetnames #print(get_sheets) TA01TA01 TA02TA02 TA03TA03 TE01TE01 YG201YG201 YG202YG202 YG203YG203 YG204YG204 YG205YG205…

Docker 數據管理介紹

默認容器的數據是保存在容器的可讀寫層,當容器被刪除時其上的數據也會丟失,所以為了實現數據的持久性則需要選擇一種數據持久技術來保存數據。官方提供了三種存儲方式:Volumes、Bind mounts和tmpfs。前面還介紹了:Docker 服務終端…

Docker 數據持久化的三種方案

容器中的數據可以存儲在容器層。但是將數據存放在容器層存在以下問題: 數據不是持久化。意思是如果容器刪除了,這些數據也就沒了 主機上的其它進程不方便訪問這些數據 對這些數據的I/O會經過存儲驅動,然后到達主機,引入了一層間…

Git 存儲原理及相關實現

Git 是目前最流行的版本控制系統,從本地開發到生產部署,我們每天都在使用 Git 進行我們的版本控制,除了日常使用的命令之外,如果想要對 Git 有更深一步的了解,那么研究下 Git 的底層存儲原理將會對理解 Git 及其使用非…

Git內部原理

Git有什么特點? fast,scalable,distributed revision control system(快速,可擴展的分布式版本控制系統) 幾乎所有操作都是本地執行 每一個clone都是整個生命周期的完整副本 the stupid content tracker&a…

git存儲原理

四種數據類型 實際上Git基于數據類型的不同,把對象分為四種:數據對象、樹對象、提交對象、標簽對象。Git文件系統的設計思路與linux文件系統相似,即將文件的內容與文件的屬性分開存儲,文件內容以“裝滿字節的袋子”存儲在文件系統…

詳解設計模式:中介者模式

中介者模式(Mediator Pattern)也被稱為調停者模式,是在 GoF 23 種設計模式中定義了的行為型模式。 中介者模式 是用來降低多個對象和類之間的通信復雜性。這種模式提供了一個中介類,該類通常處理不同類之間的通信,并支…

rebase參數以及注意事項

可以根據需要將pick參數,改變為下面代表不同作用的參數;這樣就可以對節點C和D進行不同的操作了。比如: pick:默認參數,表示不對提交節點進行任何操作,直接應用原提交節點。不創建新提交; rewor…

RPC 服務 與 HTTP 服務的區別

1、什么是RPC RPC(Remote Procedure Call)—遠程過程調用,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,為通信程序之間攜帶信…

Docker 網絡命名空間

Docker 用戶可以通過與 CNM 的 Object 以及 API 的交互來管理對應容器的網絡,下面是一個典型的容器網絡生命周期: 1、Driver要向NetworkController注冊。內置的Driver在Libnetwork內注冊,遠程的Driver則通過Plugin mechanism注冊。每一個Driv…

緩存雪崩、擊穿、穿透解決方案

用戶的數據一般都是存儲于數據庫,數據庫的數據是落在磁盤上的,磁盤的讀寫速度可以說是計算機里最慢的硬件了。 當用戶的請求,都訪問數據庫的話,請求數量一上來,數據庫很容易就奔潰的了,所以為了避免用戶直…

Ansible中的playbook詳解

首先簡單說明一下playbook,playbook是什么呢? 根本上說playbook和shell腳本沒有任何的區別,playbook就像shell一樣,也是把一堆的命令組合起來,然后加入對應條件判斷等等,在shell腳本中是一條一條的命令&am…

【Docker】容器鏡像有哪些特性

首先解釋一下什么是Docker鏡像? Docker鏡像它其實是一個模板,擁有這個模板我們才能創建我們的Docker容器,鏡像里含有啟動 docker 容器所需的文件系統結構及其內容,因此是啟動一個 docker 容器的基礎。docker 鏡像的文件內容以及一…

nginx中的location指令

1、location 介紹 location是Nginx中的塊級指令(block directive),location指令的功能是用來匹配不同的url請求,進而對請求做不同的處理和響應,這其中較難理解的是多個location的匹配順序,本文會作為重點來解釋和說明。 開始之前…