詳解建造者模式(含圖例、UML類圖、原始碼示例等)

碼農談IT發表於2023-11-22

來源:mikechen的網際網路架構

為什麼要學設計模式?設計模式有哪些優點?

  • 提升檢視框架原始碼能力
  • 提升對複雜業務程式碼的設計能力以及 code 能力
  • 為今後面試以及技術進階夯實基礎

今天我們要講的是設計模式中的建造者模式(Builder)

建造者模式(Builder)是建立型模式中的一種,在物件導向程式設計中常用,必知必會。

詳解建造者模式(含圖例、UML類圖、原始碼示例等)


01
  建造者模式的定義

建造者模式(builder):將一個複雜物件的構建與它的表示分離,使得同樣的構建過程可以建立不同的表示。

例如:

我們要定製一臺電腦,我們只需要確認配件品牌及型號,而不必知道組裝電腦的這個過程。

詳解建造者模式(含圖例、UML類圖、原始碼示例等)

這種情況下,我們可以採用建造者模式,將配件和組裝電腦的過程分離,讓構建過程和配件都能自由擴充,降低兩者之間的耦合。

02
  建造者模式的 UML 類圖

為了加深理解,我們來看下建造者模式的 UML 類圖。

詳解建造者模式(含圖例、UML類圖、原始碼示例等)

建造者模式的 4 個重要角色:

  • Product(產品類) :具體需要生成的類物件;

  • Builder(抽象建造者類):為我們需要生成的類物件,構建不同的模組屬性,即:公開構建產品類的屬性,隱藏產品類的其他功能;

  • ConcreteBuilder(具體建造者類):抽象 Builder 類的實現類,實現抽象 Builder 類定義的所有方法,並且返回一個組建好的物件;

  • Director(指揮者類):用於統一組裝流程,確定構建我們的類物件具體有哪些模組屬性,在實際應用中可以不需要這個角色,直接透過 client 處理。


03
  建造者模式的應用場景

下面是建造者模式的兩個典型應用場景。


1)建造者模式在 Java 原始碼中的體現,較為典型的就是 StringBuilder。


將指定的字串追加到此字元序列:






@Overridepublic StringBuilder append(CharSequence s) {    super.append(s);// 實現過程略    return this;}

將此字元序列用其反轉形式取代:






@Overridepublic StringBuilder reverse() {    super.reverse();// 實現過程略    return this;}


測試程式碼:









StringBuilder sb = new StringBuilder("12345");sb.append("67890");sb.reverse();System.out.println(sb);StringBuilder sb1 = new StringBuilder("12345");sb1.reverse();sb1.append("67890");System.out.println(sb1);


結果:



System.out: 0987654321System.out: 1422167890


根據 StringBuilder 不同方法的不同呼叫順序,可以生成不同的字串,這樣的操作很靈活。

2)建造者模式在很多第三方框架中也有實現。

例如,網路框架 OkHttp3中的 OkHttpClient、Request。

我們來看下 OkHttpClient 、及其內部類 OkHttpClient、Builder 的部分原始碼:

預設採用 Builder 進行建造:




public OkHttpClient() {  this(new Builder());}

由 builder 配置分發器、代理、協議以及自定義攔截器等:





















OkHttpClient(Builder builder) {  this.dispatcher = builder.dispatcher;  this.proxy = builder.proxy;  this.protocols = builder.protocols;  /** 省略大段程式碼 */  boolean isTLS = false;  for (ConnectionSpec spec : connectionSpecs) {    isTLS = isTLS || spec.isTls();  }  /** 省略大段程式碼. */  if (interceptors.contains(null)) {    throw new IllegalStateException("Null interceptor: " + interceptors);  }  if (networkInterceptors.contains(null)) {    throw new IllegalStateException("Null network interceptor: " + networkInterceptors);  }}public static final class Builder {
 public Builder() {

分發器、協議、代理的預設引數:










 dispatcher = new Dispatcher();    protocols = DEFAULT_PROTOCOLS;    proxySelector = ProxySelector.getDefault();    if (proxySelector == null) {      proxySelector = new NullProxySelector();    }  }
 Builder(OkHttpClient okHttpClient) {

反向配置分發器、代理、協議:




    this.dispatcher = okHttpClient.dispatcher;     this.proxy = okHttpClient.proxy;     this.protocols = okHttpClient.protocols;

新增所有自定義攔截器和自定義網路攔截器:




    this.interceptors.addAll(okHttpClient.interceptors);    this.networkInterceptors.addAll(okHttpClient.networkInterceptors);  }

配置代理:





  public Builder proxy(@Nullable Proxy proxy) {    this.proxy = proxy;    return this;  }

向攔截器鏈中增加自定義攔截器:






  public Builder addInterceptor(Interceptor interceptor) {    if (interceptor == null) throw new IllegalArgumentException("interceptor == null");    interceptors.add(interceptor);    return this;  }

build() 方法,生成 OkHttpClient 物件:





  public OkHttpClient build() {    return new OkHttpClient(this);  }}


04
  建造者模式的優缺點


優點:


  • 使用建造者模式可以使客戶端不必知道產品內部組成的細節;


  • 具體的建造者類之間是相互獨立的,容易擴充套件;


  • 由於具體的建造者是獨立的,因此可以對建造過程逐步細化,而不對其他的模組產生任何影響。


缺點是產生多餘的 Build 物件、Dirextor 類。


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


建造者模式與工廠模式都是讓建立與表示分離,用來服務相同的目標,讓我們寫出結構嚴謹,易懂且易擴充套件的高質量程式碼。

但是它們的作用場景、實現方式不同。

建造者模式多出一個 Builder 類,使得建立物件的靈活性大大增加,並且適用於如下場景:

  • 建立一個物件,多個同樣的方法的呼叫順序不同,產生的結果不同。例如,剛才列舉的 StringBuilder;

  • 建立一個物件,特別複雜,引數多,而且很多引數都有預設值。例如,剛才列舉的 OkHttpClient Builder 。


總結

透過本文,我們瞭解並掌握了建造者模式的概念、原理、應用場景、優缺點、實現方式等。

只有我們瞭解了每一種設計模式,實際應用時才能夠合理選型,避免因強行使用設計模式、讓程式碼更加不好維護的情況出現。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024924/viewspace-2996448/,如需轉載,請註明出處,否則將追究法律責任。

相關文章