設計模式實戰——開發中經常涉及到的建造者模式


本系列博客是自己在學習設計模式過程中收集整理的文章集合,其他文章參看設計模式傳送門

建造者模式簡介

建造者模式是一種創建型設計模式,這種模式具有很好的封裝性。使用建造者模式可以有效的封裝變化,在使用建造者模式的場景中,一般產品類和建造者類是比較穩定的,因此,將主要的業務邏輯封裝在導演類中對整體而言可以取得比較好的穩定性。

在建造者模式中,客戶端不必知道產品內部組成的細節,將產品本身與產品的創建過程解耦,使得相同的創建過程可以創建不同的產品對象。

可以更加精細地控制產品的創建過程 。將復雜產品的創建步驟分解在不同的方法中,使得創建過程更加清晰,也更方便使用程序來控制創建過程。

其次,建造者模式很容易進行擴展。如果有新的需求,通過實現一個新的建造者類就可以完成,基本上不用修改之前已經測試通過的代碼,因此也就不會對原有功能引入風險。符合開閉原則。

建造者模式通常包含以下角色

抽象建造者類(builder):為創建product對象而指定各個組件的抽象接口

具體建造類(concreteBuilder):實現builder接口,重寫方法構建不同的表示

產品類(product):具體的產品

指揮者類(director):構建一個使用builder接口的對象

JDK中的建造者模式——StringBuilder

StringBuilder類是JDK中比較典型的建造者模式的體現。我先看下這個類的類圖:

我們根據上圖看下各個角色的對應情況:

  • StringBuilder:指揮者角色,持有具體建造者的引用,由於StringBuilder繼承了AbstractStringBuilder,這里StringBuilder通過super來作為具體建造者的引用。

  • AbstractStringBuilder:具體建造者,它實現了appendable接口的append(Character c)方法。

  • Appendable:抽象建造者,定義了創建對象的接口。

  • String:產品角色。

另外,StringBuffer也是使用了建造者模式。兩者的唯一區別就是StringBuffer使用了synchronized來保證線程安全,而StringBuilder不是線程安全的。

其實,建造者模式在我們平時開發中更多的體現就是像StringBuilder.append這樣的鏈式調用。其中StringBuilder就是指揮官角色,append方法是創建產品細節的過程,當我們創建完產品后就可以調用toString方法生成具體的產品。比如下面的代碼


String str = new StringBuilder().append()
                                .append()
                                .toString();

這樣類似的代碼還有很多,比如

Header header = new HeaderBuilder()
   .setClientId(SOAHeader.SOAP_CLIENT_ID)
   .setCorrelationId(SOAHeader.SOAP_CORRELATION_ID)
   .buildHeader();

在平時開發過程中,如果我們看到上面類似的代碼,可能就是用了建造者模式。我們平時要留意這樣的代碼,看看作者為什么要這樣設計系統,對我們的代碼提升很有幫助。這也是我整理總結開發框架中常見設計模式的用意。

Spring中的建造者模式

Spring是Java開發者最常用的開發框架。有人說Spring的源代碼就是設計模式的盛宴。看Spring的源代碼是很好的學習設計模式的一種方式。

在Spring框架中,常涉及到的建造者模式有:

  • UriComponentsBuilder
  • BeanDefinitionBuilder

其中BeanDefinitionBuilder較底層,我們平時不太會用到。這里我們通過UriComponentsBuilder來講述Spring中的建造者模式。

下面的代碼中,我們Spring中的restTemplate工具調用遠程接口。在調用前需要先構建URL參數。這邊就是使用了UriComponentsBuilder來構建的。

 UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("127.0.0.1:8080").
                path("/test").build(true);
 URI uri = uriComponents.toUri();
 
RequestEntity<JSONObject> requestEntity = RequestEntity.post(uri).
                //添加cookie(這邊有個問題,假如我們要設置cookie的生命周期,作用域等參數我們要怎么操作)
                header(HttpHeaders.COOKIE,"key1=value1").
                //添加header
                header(("MyRequestHeader", "MyValue")
                accept(MediaType.APPLICATION_JSON).
                contentType(MediaType.APPLICATION_JSON).
                body(requestParam);
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(requestEntity,JSONObject.class);
//響應結果
JSONObject responseEntityBody = responseEntity.getBody();

Spring中的設計模式有很多,我們平時使用時可以細心關注下。相信肯定會有收獲。

MyBatis中的建造者模式

MyBatis中最經典的建造者模式肯定是獲取SqlSessionFactory的過程。

下面是獲取SqlSessionFactory的典型用法。

CopyClassPathResource resource = new ClassPathResource("mybatis-config.xml");
InputStream inputStream = resource.getInputStream();
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

通過上面代碼發現,創建SqlSessionFactory的代碼在SqlSessionFactoryBuilder中,進去一探究竟:

Copy//整個過程就是將配置文件解析成Configration對象,然后創建SqlSessionFactory的過程
//Configuration是SqlSessionFactory的一個內部屬性
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
    
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

代碼比較簡單,就不具體分析了。這里還是對號入座,列舉下各個角色。

  • SqlSessionFactoryBuilder:指揮者角色
  • BaseBuilder:抽象Builder
  • XMLConfigBuilder:具體的Builder
  • SqlSessionFactory:需要被創建的產品

感悟

學習設計模式光學習不行,因為這個東西比較抽象。你必須結合具體的項目框架來看才能有比較深的感悟。

平時如果有空余時間可以自己動手,使用設計模式寫一些小的框架。還有就是多看看那些主流開源框架的源代碼,這些代碼中都有很對設計模式的體現。結合設計模式的理論知識,看看這些框架中為什么要用這些模式,比你光看肯定收獲要多。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM