<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          建造者模式——不止提高代碼逼格

          共 10939字,需瀏覽 22分鐘

           ·

          2021-06-11 04:32

          點擊藍色“JavaKeeper”關(guān)注我喲加個“星標(biāo)”,一起成長,做牛逼閃閃的技術(shù)人28926185129676e5a64f01bc0fd0159b.webp

          Keeper導(dǎo)讀:StringBuilder 你肯定用過,JDK 中的建造者模式

          lombok 中的 @Bulider,你可能也用過,恩,這也是我們要說的建造者模式

          簡介

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

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

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

          0d5a1813e6d980aba3a2b49ce58be3e2.webp

          hello world

          程序員麼,先上個 hello world 熱熱身

          public class User {

              private Long id;
              private String name;
              private Integer age;  //可選
              private String desc; //可選

              private User(Builder builder) {
                  this.id = builder.id;
                  this.name = builder.name;
                  this.age = builder.age;
                  this.desc = builder.desc;
              }

              public static Builder newBuilder(Long id, String name) {
                  return new Builder(id, name);
              }

              public Long getId() {return id;}
              public String getName() {return name;}
              public Integer getAge() {return age;}
              public String getDesc() {return desc;}

              @Override
              public String toString() {
                  return "Builder{" +
                          "id=" + id +
                          ", name='" + name + '\'' +
                          ", age=" + age +
                          ", desc='" + desc + '\'' +
                          '}';
              }

              public static class Builder {
                  private Long id;
                  private String name;
                  private Integer age;
                  private String desc;

                  private Builder(Long id, String name) {
                      Assert.assertNotNull("標(biāo)識不能為空",id);
                      Assert.assertNotNull("名稱不能為空",name);
                      this.id = id;
                      this.name = name;
                  }
                  public Builder age(Integer age) {
                      this.age = age;
                      return this;
                  }
                  public Builder desc(String desc) {
                      this.desc = desc;
                      return this;
                  }
                  public User build() {
                      return new User(this);
                  }

              }

              public static void main(String[] args) {
                  User user = User.newBuilder(1L"starfish").age(22).desc("test").build();
                  System.out.println(user.toString());
              }
          }

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

          主要優(yōu)點:

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

          主要缺點:

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

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

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

          高射炮打蚊子——不合算

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

          這時候才是構(gòu)造器模式上場的時候

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

          我們接著扯~

          結(jié)構(gòu)

          f0d9d52cd01dd034bfa28e436c91f668.webp

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

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

          demo

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

          c33132dbc97ebfcdc9b05c73e518802d.webp

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

          public interface CarBuilder {
              void setCarType(CarType type);
              void setSeats(int seats);
              void setEngine(Engine engine);
              void setGPS(GPS gps);
          }

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

          public class SportsCarBuilder implements CarBuilder {

              private CarType carType;
              private int seats;
              private Engine engine;
              private GPS gps;

              @Override
              public void setCarType(CarType type) {
                  this.carType = type;
              }

              @Override
              public void setSeats(int seats) {
                  this.seats = seats;
              }

              @Override
              public void setEngine(Engine engine) {
                  this.engine = engine;
              }

              @Override
              public void setGPS(GPS gps) {
                  this.gps = gps;
              }

              public Car getResult() {
                  return new Car(carType, seats, engine, gps);
              }
          }

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

          @Setter
          @Getter
          @ToString
          public class Car {

              private final CarType carType;
              private final int seats;
              private final Engine engine;
              private final GPS gps;
              private double fuel;

              public Car(CarType carType,int seats,Engine engine,GPS gps){
                  this.carType = carType;
                  this.seats = seats;
                  this.engine = engine;
                  this.gps = gps;
              }
          }

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

          public class Director {

              public void constructSportsCar(CarBuilder builder){
                  builder.setCarType(CarType.SPORTS_CAR);
                  builder.setSeats(2);
                  builder.setEngine(new Engine(2.0,0));
                  builder.setGPS(new GPS());
              }

              public void constructCityCar(CarBuilder builder){
                  builder.setCarType(CarType.CITY_CAR);
                  builder.setSeats(4);
                  builder.setEngine(new Engine(1.5,0));
                  builder.setGPS(new GPS());
              }

              public void constructSUVCar(CarBuilder builder){
                  builder.setCarType(CarType.SUV);
                  builder.setSeats(4);
                  builder.setEngine(new Engine(2.5,0));
                  builder.setGPS(new GPS());
              }

          }

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

          public class Client {

              public static void main(String[] args) {
                  Director director = new Director();
                  SportsCarBuilder builder = new SportsCarBuilder();
                  director.constructSportsCar(builder);

                  Car car = builder.getResult();
                  System.out.println(car.toString());
              }
          }

          適用場景

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

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

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

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

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

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

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

          VS 抽象工廠

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

          最后

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

          公眾號回復(fù) ”設(shè)計模式“,領(lǐng)取 10 本設(shè)計模式 pdf 書籍

          參考

          • refactoringguru.cn

          5d776d71494ffb2ca08d5c5ca16a1aec.webp

          5bc797e163860078bf0c9a3ff6c601f6.webp

          管道模式



          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日日嗨av一区二区三区免费 | 91精品国产91久久久久久 | 久久国产成人精品Av | 久久精品国产亚洲AV无码偷窥 | 插插久久|