自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

建造者模式——不止提高代碼檔次

開(kāi)發(fā) 前端
建造者模式是一種創(chuàng)建型設(shè)計(jì)模式, 使你能夠分步驟創(chuàng)建復(fù)雜對(duì)象。它允許用戶只通過(guò)指定復(fù)雜對(duì)象的類(lèi)型和內(nèi)容就可以構(gòu)建它們,用戶不需要知道內(nèi)部的具體構(gòu)建細(xì)節(jié)。

[[405080]]

本文轉(zhuǎn)載自微信公眾號(hào)「JavaKeeper」,作者海星。轉(zhuǎn)載本文請(qǐng)聯(lián)系JavaKeeper公眾號(hào)。

簡(jiǎn)介

Builder Pattern,中文翻譯為建造者模式或者構(gòu)建者模式,也有人叫它生成器模式。

建造者模式是一種創(chuàng)建型設(shè)計(jì)模式, 使你能夠分步驟創(chuàng)建復(fù)雜對(duì)象。它允許用戶只通過(guò)指定復(fù)雜對(duì)象的類(lèi)型和內(nèi)容就可以構(gòu)建它們,用戶不需要知道內(nèi)部的具體構(gòu)建細(xì)節(jié)。

定義:將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。

hello world

程序員麼,先上個(gè) hello world 熱熱身

  1. public class User { 
  2.  
  3.     private Long id; 
  4.     private String name
  5.     private Integer age;  //可選 
  6.     private String desc; //可選 
  7.  
  8.     private User(Builder builder) { 
  9.         this.id = builder.id; 
  10.         this.name = builder.name
  11.         this.age = builder.age; 
  12.         this.desc = builder.desc
  13.     } 
  14.  
  15.     public static Builder newBuilder(Long id, String name) { 
  16.         return new Builder(id, name); 
  17.     } 
  18.  
  19.     public Long getId() {return id;} 
  20.     public String getName() {return name;} 
  21.     public Integer getAge() {return age;} 
  22.     public String getDesc() {return desc;} 
  23.  
  24.     @Override 
  25.     public String toString() { 
  26.         return "Builder{" + 
  27.                 "id=" + id + 
  28.                 ", name='" + name + '\'' + 
  29.                 ", age=" + age + 
  30.                 ", desc='" + desc + '\'' + 
  31.                 '}'
  32.     } 
  33.  
  34.     public static class Builder { 
  35.         private Long id; 
  36.         private String name
  37.         private Integer age; 
  38.         private String desc
  39.  
  40.         private Builder(Long id, String name) { 
  41.             Assert.assertNotNull("標(biāo)識(shí)不能為空",id); 
  42.             Assert.assertNotNull("名稱不能為空",name); 
  43.             this.id = id; 
  44.             this.name = name
  45.         } 
  46.         public Builder age(Integer age) { 
  47.             this.age = age; 
  48.             return this; 
  49.         } 
  50.         public Builder desc(String desc) { 
  51.             this.desc = desc
  52.             return this; 
  53.         } 
  54.         public User build() { 
  55.             return new User(this); 
  56.         } 
  57.  
  58.     } 
  59.  
  60.     public static void main(String[] args) { 
  61.         User user = User.newBuilder(1L, "starfish").age(22).desc("test").build(); 
  62.         System.out.println(user.toString()); 
  63.     } 

這樣的代碼有什么優(yōu)缺點(diǎn)呢?

主要優(yōu)點(diǎn):

  1. 明確了必填參數(shù)和可選參數(shù),在構(gòu)造方法中進(jìn)行驗(yàn)證;
  2. 可以定義為不可變類(lèi),初始化后屬性字段值不可變更;
  3. 賦值代碼可讀性較好,明確知道哪個(gè)屬性字段對(duì)應(yīng)哪個(gè)值;
  4. 支持鏈?zhǔn)椒椒ㄕ{(diào)用,相比于調(diào)用 Setter 方法,代碼更簡(jiǎn)潔。

主要缺點(diǎn):

  1. 代碼量較大,多定義了一個(gè) Builder 類(lèi),多定義了一套屬性字段,多實(shí)現(xiàn)了一套賦值方法;
  2. 運(yùn)行效率低,需要先創(chuàng)建 Builder 實(shí)例,再賦值屬性字段,再創(chuàng)建目標(biāo)實(shí)例,最后拷貝屬性字段。

當(dāng)然,以上代碼,就可以通過(guò) Lombok 的 @Builder 簡(jiǎn)化代碼

如果我們就那么三三兩兩個(gè)參數(shù),直接構(gòu)造函數(shù)配合 set 方法就能搞定的,就不用套所謂的模式了。

高射炮打蚊子——不合算

假設(shè)有這樣一個(gè)復(fù)雜對(duì)象, 在對(duì)其進(jìn)行構(gòu)造時(shí)需要對(duì)諸多成員變量和嵌套對(duì)象進(jìn)行繁復(fù)的初始化工作。這些初始化代碼通常深藏于一個(gè)包含眾多參數(shù)且讓人基本看不懂的構(gòu)造函數(shù)中;甚至還有更糟糕的情況, 那就是這些代碼散落在客戶端代碼的多個(gè)位置。

這時(shí)候才是構(gòu)造器模式上場(chǎng)的時(shí)候

上邊的例子,其實(shí)屬于簡(jiǎn)化版的建造者模式,只是為了方便構(gòu)建類(lèi)中的各個(gè)參數(shù),”正經(jīng)“的和這個(gè)有點(diǎn)差別,更傾向于用同樣的構(gòu)建過(guò)程分步創(chuàng)建不同的產(chǎn)品類(lèi)。

我們接著扯~

結(jié)構(gòu)

從 UML 圖上可以看到有 4 個(gè)不同的角色

  • 抽象建造者(Builder):創(chuàng)建一個(gè) Produc 對(duì)象的各個(gè)部件指定的接口/抽象類(lèi)
  • 具體建造者(ConcreteBuilder):實(shí)現(xiàn)接口,構(gòu)建和裝配各個(gè)組件
  • 指揮者/導(dǎo)演類(lèi)(Director):構(gòu)建一個(gè)使用 Builder 接口的對(duì)象。負(fù)責(zé)調(diào)用適當(dāng)?shù)慕ㄔ煺邅?lái)組建產(chǎn)品,導(dǎo)演類(lèi)一般不與產(chǎn)品類(lèi)發(fā)生依賴關(guān)系,與導(dǎo)演類(lèi)直接交互的是建造者類(lèi)。
  • 產(chǎn)品類(lèi)(Product):一個(gè)具體的產(chǎn)品對(duì)象

demo

假設(shè)我是個(gè)汽車(chē)工廠,需求就是能造各種車(chē)(或者造電腦、造房子、做煎餅、生成不同文件TextBuilder、HTMLBuilder等等,都是一個(gè)道理)

1、生成器(Builder)接口聲明在所有類(lèi)型生成器中通用的產(chǎn)品構(gòu)造步驟

  1. public interface CarBuilder { 
  2.     void setCarType(CarType type); 
  3.     void setSeats(int seats); 
  4.     void setEngine(Engine engine); 
  5.     void setGPS(GPS gps); 

2、具體的生成器(Concrete Builders)提供構(gòu)造過(guò)程的不同實(shí)現(xiàn)

  1. public class SportsCarBuilder implements CarBuilder { 
  2.  
  3.     private CarType carType; 
  4.     private int seats; 
  5.     private Engine engine; 
  6.     private GPS gps; 
  7.  
  8.     @Override 
  9.     public void setCarType(CarType type) { 
  10.         this.carType = type; 
  11.     } 
  12.  
  13.     @Override 
  14.     public void setSeats(int seats) { 
  15.         this.seats = seats; 
  16.     } 
  17.  
  18.     @Override 
  19.     public void setEngine(Engine engine) { 
  20.         this.engine = engine; 
  21.     } 
  22.  
  23.     @Override 
  24.     public void setGPS(GPS gps) { 
  25.         this.gps = gps; 
  26.     } 
  27.  
  28.     public Car getResult() { 
  29.         return new Car(carType, seats, engine, gps); 
  30.     } 

3、產(chǎn)品(Products)是最終生成的對(duì)象

  1. @Setter 
  2. @Getter 
  3. @ToString 
  4. public class Car { 
  5.  
  6.     private final CarType carType; 
  7.     private final int seats; 
  8.     private final Engine engine; 
  9.     private final GPS gps; 
  10.     private double fuel; 
  11.  
  12.     public Car(CarType carType,int seats,Engine engine,GPS gps){ 
  13.         this.carType = carType; 
  14.         this.seats = seats; 
  15.         this.engine = engine; 
  16.         this.gps = gps; 
  17.     } 

4、主管(Director)類(lèi)定義調(diào)用構(gòu)造步驟的順序,這樣就可以創(chuàng)建和復(fù)用特定的產(chǎn)品配置(Director 類(lèi)的構(gòu)造函數(shù)的參數(shù)是 CarBuilder,但實(shí)際上沒(méi)有實(shí)例傳遞出去作參數(shù),因?yàn)?CarBuilder 是接口或抽象類(lèi),無(wú)法產(chǎn)生對(duì)象實(shí)例,實(shí)際傳遞的是 Builder 的子類(lèi),根據(jù)子類(lèi)類(lèi)型,決定生產(chǎn)內(nèi)容)

  1. public class Director { 
  2.  
  3.     public void constructSportsCar(CarBuilder builder){ 
  4.         builder.setCarType(CarType.SPORTS_CAR); 
  5.         builder.setSeats(2); 
  6.         builder.setEngine(new Engine(2.0,0)); 
  7.         builder.setGPS(new GPS()); 
  8.     } 
  9.  
  10.     public void constructCityCar(CarBuilder builder){ 
  11.         builder.setCarType(CarType.CITY_CAR); 
  12.         builder.setSeats(4); 
  13.         builder.setEngine(new Engine(1.5,0)); 
  14.         builder.setGPS(new GPS()); 
  15.     } 
  16.  
  17.     public void constructSUVCar(CarBuilder builder){ 
  18.         builder.setCarType(CarType.SUV); 
  19.         builder.setSeats(4); 
  20.         builder.setEngine(new Engine(2.5,0)); 
  21.         builder.setGPS(new GPS()); 
  22.     } 
  23.  

5、客戶端使用(最終結(jié)果從建造者對(duì)象中獲取,主管并不知道最終產(chǎn)品的類(lèi)型)

  1. public class Client { 
  2.  
  3.     public static void main(String[] args) { 
  4.         Director director = new Director(); 
  5.         SportsCarBuilder builder = new SportsCarBuilder(); 
  6.         director.constructSportsCar(builder); 
  7.  
  8.         Car car = builder.getResult(); 
  9.         System.out.println(car.toString()); 
  10.     } 

適用場(chǎng)景

適用場(chǎng)景其實(shí)才是理解設(shè)計(jì)模式最重要的,只要知道這個(gè)業(yè)務(wù)場(chǎng)景需要什么模式,網(wǎng)上浪~程序員能不會(huì)嗎

  • 使用建造者模式可避免重疊構(gòu)造函數(shù)的出現(xiàn)。

假設(shè)你的構(gòu)造函數(shù)中有 N 個(gè)可選參數(shù),那 new 各種實(shí)例的時(shí)候就很麻煩,需要重載構(gòu)造函數(shù)多次

  • 當(dāng)你希望使用代碼創(chuàng)建不同形式的產(chǎn)品 (例如石頭或木頭房屋) 時(shí), 可使用建造者模式。

如果你需要?jiǎng)?chuàng)建的各種形式的產(chǎn)品, 它們的制造過(guò)程相似且僅有細(xì)節(jié)上的差異, 此時(shí)可使用建造者模式。

  • 使用生成器構(gòu)造組合樹(shù)或其他復(fù)雜對(duì)象。

建造者模式讓你能分步驟構(gòu)造產(chǎn)品。你可以延遲執(zhí)行某些步驟而不會(huì)影響最終產(chǎn)品。你甚至可以遞歸調(diào)用這些步驟, 這在創(chuàng)建對(duì)象樹(shù)時(shí)非常方便。

VS 抽象工廠

抽象工廠模式實(shí)現(xiàn)對(duì)產(chǎn)品家族的創(chuàng)建,一個(gè)產(chǎn)品家族是這樣的一系列產(chǎn)品:具有不同分類(lèi)維度的產(chǎn)品組合,采用抽象工廠模式不需要關(guān)心抽象過(guò)程,只關(guān)心什么產(chǎn)品由什么工廠生產(chǎn)即可。而建造者模式則是要求按照指定的藍(lán)圖建造產(chǎn)品,它的主要目的是通過(guò)組裝零配件而生產(chǎn)一個(gè)新的產(chǎn)品。

最后

設(shè)計(jì)模式,這玩意看簡(jiǎn)單的例子,肯定能看得懂,主要是結(jié)合自己的業(yè)務(wù)思考怎么應(yīng)用,讓系統(tǒng)設(shè)計(jì)更完善,懂了每種模式后,可以找找各種框架源碼或在 github 搜搜相關(guān)內(nèi)容,看看實(shí)際中是怎么應(yīng)用的。

參考

 

refactoringguru.cn

 

責(zé)任編輯:武曉燕 來(lái)源: JavaKeeper
相關(guān)推薦

2020-10-20 13:33:00

建造者模式

2021-10-26 00:21:19

設(shè)計(jì)模式建造者

2021-01-21 05:34:14

設(shè)計(jì)模式建造者

2021-05-11 08:54:59

建造者模式設(shè)計(jì)

2021-04-14 09:02:22

模式 設(shè)計(jì)建造者

2011-07-14 14:46:46

設(shè)計(jì)模式

2021-07-28 10:02:54

建造者模式代碼

2024-02-19 08:38:34

建造者模式Android設(shè)計(jì)模式

2022-11-01 15:25:01

構(gòu)建者模式Go 語(yǔ)言

2025-04-25 08:23:20

2020-11-23 10:02:04

開(kāi)發(fā)者

2020-11-16 22:04:20

開(kāi)發(fā)者

2022-10-09 08:48:13

配置化建造者參數(shù)

2023-11-08 14:45:14

AIGC生成式人工智能

2010-08-27 10:34:51

程序員

2023-06-05 18:25:52

物聯(lián)網(wǎng)大數(shù)據(jù)

2017-06-26 09:40:50

Python代碼寫(xiě)法

2017-07-07 16:57:35

代碼Python

2010-01-12 09:30:03

Windows 7快捷模式

2021-07-20 08:52:20

命令模式中介者模式設(shè)計(jì)模式
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)