欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設計模式之java橋接模式詳解

 更新時間:2021年09月16日 14:51:59   作者:張維鵬  
這篇文章主要介紹了Java設計模式之橋接模式,結合實例形式詳細分析了橋接模式的概念、功能、Java實現(xiàn)方法及相關注意事項,需要的朋友可以參考下

一、什么是橋接模式:

橋接,顧名思義,就是用來連接兩個部分,使得兩個部分可以互相通訊,橋接模式的作用就是為被分離的抽象部分和實現(xiàn)部分搭橋。在現(xiàn)實生活中一個物品在搭配不同的配件時會產(chǎn)生不同的動作和結果,例如一輛賽車搭配的是硬胎或者是軟胎就能夠在干燥的馬路上行駛,而如果要在下雨的路面行駛,就需要搭配雨胎了,這種根據(jù)行駛的路面不同,需要搭配不同的輪胎的變化的情況,我們從軟件設計的角度來分析,就是一個系統(tǒng)由于自身的邏輯,會有兩個或多個維度的變化,而為了應對這種變化,我們就可以使用橋接模式來進行系統(tǒng)的解耦。 橋接模式將一個系統(tǒng)的抽象部分和實現(xiàn)部分分離,使它們都可以獨立地進行變化,對應到上面就是賽車的種類可以相對變化,輪胎的種類可以相對變化,形成一種交叉的關系,最后的結果就是一種賽車對應一種輪胎就能夠成功產(chǎn)生一種結果和行為。

橋接模式將系統(tǒng)的抽象部分與實現(xiàn)部分分離解耦,使他們可以獨立的變化。為了達到讓抽象部分和實現(xiàn)部分獨立變化的目的,橋接模式使用組合關系來代替繼承關系,抽象部分擁有實現(xiàn)部分的接口對象,從而能夠通過這個接口對象來調(diào)用具體實現(xiàn)部分的功能。也就是說,橋接模式中的橋接是一個單方向的關系,只能夠抽象部分去使用實現(xiàn)部分的對象,而不能反過來。

橋接模式符合“開閉原則”,提高了系統(tǒng)的可拓展性,在兩個變化維度中任意擴展一個維度,都不需要修改原來的系統(tǒng);并且實現(xiàn)細節(jié)對客戶不透明,可以隱藏實現(xiàn)細節(jié)。但是由于聚合關系建立在抽象層,要求開發(fā)者針對抽象進行編程,這增加系統(tǒng)的理解和設計難度。

所以,橋接模式一般適用于以下幾種應用場景:

(1)系統(tǒng)需要在構件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態(tài)的繼承聯(lián)系,則可以通過橋接模式使他們在抽象層建立一個關聯(lián)關系;

(2)系統(tǒng)不希望使用繼承或因為多層次繼承導致系統(tǒng)類的個數(shù)急劇增加時

(3)一個類存在兩個獨立變化的維度,而這兩個維度都需要進行擴展。

二、UML結構圖:

抽象化角色 Abstraction:定義抽象的接口,包含一個對實現(xiàn)化角色的引用,抽象角色的方法需要調(diào)用實現(xiàn)化角色;擴展抽象化角色 RefinedAbstraction:抽象化角色的子類,一般對抽象部分的方法進行完善和擴展,實現(xiàn)父類中的業(yè)務方法,并通過組合/聚合關系調(diào)用實現(xiàn)化角色中的業(yè)務方法實現(xiàn)化角色 Implementor:定義具體行為、具體特征的應用接口,供擴展抽象化角色使用,一般情況下是由實現(xiàn)化角色提供基本的操作,而抽象化角色定義基于實現(xiàn)部分基本操作的業(yè)務方法;具體實現(xiàn)化角色 ConcreteImplementor:完善實現(xiàn)化角色中定義的具體邏輯。

三、代碼實現(xiàn):

Implementor 接口類:

public interface Implementor {
    void operationImpl();
}

ConcreteImplementor 接口實現(xiàn)類:

public class ConcreteImplementorA implements Implementor{
    @Override
    public void operationImpl() {
        //具體實現(xiàn)
    }
}
public class ConcreteImplementorB implements Implementor{
    @Override
    public void operationImpl() {
        //具體實現(xiàn)
    }
}

Abstraction 抽象類:

public abstract class Abstraction {
    private Implementor implementor;
    public Abstraction(Implementor implementor) {
        this.implementor = implementor;
    }
    public void operation() {
        implementor.operationImpl();
    }
}

RefinedAbstraction 抽象類的具體實現(xiàn):

public class RefinedAbstraction extends Abstraction{
    public RefinedAbstraction(Implementor implementor) {
        super(implementor);
    }
    public void refinedOperation() {
        //對 Abstraction 中的 operation 方法進行擴展
    }
}

看了這段通用代碼之后,橋接模式的結構應該就很清楚了,需要注意的是 RefinedAbstraction 根據(jù)實際情況是可以有多個的。 當然上面的 UML 類圖和通用代碼只是最常用的實現(xiàn)方式而已,在實際使用中可能會有其他的情況,比如 Implementor 只有一個類的情況,雖然這時候可以不去創(chuàng)建 Implementor 接口,精簡類的層次,但是我建議還是需要抽象出實現(xiàn)部分的接口。

四、JDBC源碼解析-橋接模式:

該部分引用自:JDBC和橋接模式 - 枯落 - 博客園

Java 中,我們使用 JDBC 連接數(shù)據(jù)庫時,在各個數(shù)據(jù)庫之間進行切換,基本不需要動太多的代碼,原因就是使用了橋接模式,JDBC 提供統(tǒng)一接口,每種類型的數(shù)據(jù)庫提供各自的實現(xiàn),然后由橋接類創(chuàng)建一個連接數(shù)據(jù)庫的驅(qū)動,使用某一個數(shù)據(jù)庫的時候只需要切換一下就行。接下來我們就對 JDBC 的源碼做下剖析:

通過原生JDBC API連接MySQL數(shù)據(jù)庫,則有如下示例代碼:

Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://<host>:<port>/<database>");

短短兩行代碼難以看出橋接模式的結構,下面先對源碼進行一定的分析,理解各個類和接口之間的關系:

1、源碼分析:

(1)Class.forName() 方法:

該方法將返回與給定字符串名的類或接口相關聯(lián)的 java.lang.Class 類對象,用于在程序運行時動態(tài)加載該類或該接口到當前線程中,如果 Class.forName() 加載的是一個類,也會執(zhí)行類中包含的static { } 靜態(tài)代碼段

(2)com.mysql.cj.jdbc.Driver 類

MySQL 將具體的 java.sql.Driver 接口的實現(xiàn)放到了 NonRegisteringDriver 中,com.mysql.cj.jdbc.Driver 類僅包含一段靜態(tài)代碼,具體類圖如下:

其中最關鍵的是靜態(tài)代碼段中的 DriverManager.registerDriver(new Driver()) ,它會在客戶端調(diào)用Class.forName() 方法加載 com.mysql.cj.jdbc.Driver 類的同時被執(zhí)行,Driver 類自身的一個實例被注冊到 DriverManager(即保存到 DriverManager 的靜態(tài)字段 registeredDrivers 內(nèi)),注冊過程的源碼如下:

public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da)
throws SQLException {
  /* Register the driver if it has not already been added to our list */
  if(driver != null) {
    registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
  } else {
    // This is for compatibility with the original DriverManager
    throw new NullPointerException();
  }
  println("registerDriver: " + driver);
}

registeredDrivers 靜態(tài)字段的類型是實現(xiàn)了 List 接口的 CopyOnWriteArrayList 類,它能夠保存進一步封裝 java.sql.Driver 接口的 DriverInfo 類實例,DriverInfo 類的聲明代碼如下:

class DriverInfo {
  final Driver driver;
  DriverAction da;
  DriverInfo(Driver driver, DriverAction action) {
    this.driver = driver;
    da = action;
  }
  // ……
}

DriverInfo 還包裝了 DriverAction,DriverAction 會在Driver被取消注冊時被調(diào)用,在 MySQL 的 Driver 在向 DriverManager 進行注冊時,DriverAction 被設置為 null

(3)DriverManager 類:

由上面的分析可得,Class.forName() 方法調(diào)用后,com.mysql.cj.jdbc.Driver 類被加載,并執(zhí)行static { } 靜態(tài)代碼段,將 com.mysql.cj.jdbc.Driver 類實例注冊到 DriverManager 中。然后,客戶端會調(diào)用 DriverManager.getConnection() 方法獲取一個 Connection 數(shù)據(jù)庫連接實例,該方法的部分源碼如下:

private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {
  // ……
  for(DriverInfo aDriver : registeredDrivers) {
    // If the caller does not have permission to load the driver then
    // skip it.
    if(isDriverAllowed(aDriver.driver, callerCL)) {
      try {
        println(" trying " + aDriver.driver.getClass().getName());
        Connection con = aDriver.driver.connect(url, info);
        if (con != null) {
          // Success!
          println("getConnection returning " + aDriver.driver.getClass().getName());
          return (con);
        }
      } catch (SQLException ex) {
        if (reason == null) {
          reason = ex;
        }
      }
    } else {
      println(" skipping: " + aDriver.getClass().getName());
    }
  }
  // ……
}

DriverManager.getConnection() 方法會遍歷 registeredDrivers 靜態(tài)字段,獲取字段內(nèi)保存的每一個 Driver 來嘗試響應客戶端的數(shù)據(jù)庫連接請求,若所有 Driver 都連接數(shù)據(jù)庫失敗,則提示連接失敗信息

(4)Connection接口

Connection 代表和特定數(shù)據(jù)庫的連接會話,能夠執(zhí)行SQL語句并在連接的上下文中返回執(zhí)行結果。因此,DriverManager.getConnection() 方法返回的 Connection 數(shù)據(jù)庫連接實例根據(jù)不同的數(shù)據(jù)庫有不同的實現(xiàn),MySQL 的 Connection 接口實現(xiàn)關系如下:

2、源碼類圖:

根據(jù)源碼的分析,繪制類圖如下:

對 Driver 和 Connection 進行抽象,繪制類圖如下:

橋接模式通過聚合關系代替繼承關系,實現(xiàn)抽象化和實現(xiàn)化部分的解耦。以上述 JDBC 在 MySQL 中的簡略類圖為例,抽象化部分有 DriverManager,實現(xiàn)化部分有 Driver 接口和 Connection 接口。對于不同的數(shù)據(jù)庫,Driver接口和Connection接口都有自己獨特的實現(xiàn)類。

但是,和 Driver 接口不同的是,Connection 接口與 DriverManager 類的關系只是聯(lián)系較弱的依賴關系,并不符合橋接模式的定義和特點。因此,在考慮橋接模式的情況下,可以再次將類圖進行簡化:

最后,我們將其它數(shù)據(jù)庫的Driver接口實現(xiàn)也考慮在內(nèi),繪制類圖如下:

橋接模式中的實現(xiàn)化角色 (Implementor) 對應上圖的 Driver 接口,具體實現(xiàn)化 (Concrete Implementor) 角色對應 MysqlDriver、OracleDriver 和 MariadbDriver,擴展抽象化 (Refined Abstraction) 角色對應 DriverManager,不具有抽象化 (Abstraction) 角色作為擴展抽象化角色的父類

3、對 JDBC 的觀點:

(1)觀點一:JDBC 的橋接模式是一中簡化的橋接模式

橋接模式的主要應用場景是某個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展,而現(xiàn)在僅有 Driver 一個變化維度,DriverManager 沒有抽象化父類,它本身也沒有任何子類,因此我認為,在 JDBC 中,是一種簡化的橋接模式。

倘若 JDBC 針對 Connection 接口的設計不是將它作為 Driver 和 DriverManager 的"依賴"來處理,而是也作為一個變化的維度加入到橋接模式,或許能夠更好地體現(xiàn)JDBC對橋接模式的實現(xiàn),一種"假想"的橋接模式如下:

(2)觀點二:JDBC采用的是策略模式而不是橋接模式

問題來源知乎:jdbc是橋接模式還是策略模式? - 知乎

因為這確實和策略模式十分相似,如果把橋接模式的抽象部分簡化來看,不去設計Abstraction,也就是用 Refined Abstraction 代替 Abstraction,那么就類似于策略模式的 Context 來使用接口的對象。

但是,橋接模式和策略模式的目的是不一樣的,策略模式屬于對象行為模式(描述對象之間怎樣相互協(xié)作共同完成單個對象都無法單獨完成的任務,以及怎樣分配職責),它的目的是封裝一系列的算法,使得算法可以相互替代,并在程序運行的不同時刻選擇合適的算法。而橋接模式屬于對象結構模式(描述如何將對象按某種布局組成更大的結構),它的目的是將抽象與實現(xiàn)分離,使它們可以獨立變化

因此,從設計的目的來看,JDBC采用的并不是策略模式,在一段程序中數(shù)據(jù)庫驅(qū)動并不存在頻繁地相互替換

(3)觀點三:變化的維度一個是平臺,另一個是數(shù)據(jù)庫

這是我認同的一個觀點,引用原文的話:變的是平臺和數(shù)據(jù)庫,平臺在 JVM 這個層面就解決了,因為所有操作系統(tǒng) Java 基本都會提供對應JDK,這也是 "Once Write,Run AnyWhere" 的原因。而數(shù)據(jù)庫則是依托公司的具體實現(xiàn),各個公司都提供對應的 Driver 類,我用 DriverManager 類進行懶加載.

考慮數(shù)據(jù)庫的實際應用場景,我們可能在不同的操作系統(tǒng)上使用不同的數(shù)據(jù)庫,但是JVM的平臺無關性使得我們不再有操作系統(tǒng)層面上的變化。假設不存在JVM,那么不同的客戶端加載和運行數(shù)據(jù)庫驅(qū)動程序的代碼自然也各有不同,即 DriverManager 會因操作系統(tǒng)的變化而變化,不同的操作系統(tǒng)可以有不同的注冊 Driver 的方式,不過因為存在JVM,我們現(xiàn)在不再有"平臺"這一變化維度了

(4)觀點四:變化的維度一個是客戶端應用系統(tǒng),另一個是數(shù)據(jù)庫

問題來源:java設計模式-橋梁模式(橋接模式 Bridge) - 簡書

一個比較獨特的觀點,引用原文的話:應用系統(tǒng)作為一個等級結構,與 JDBC 驅(qū)動器這個等級結構是相對獨立的,它們之間沒有靜態(tài)的強關聯(lián)。應用系統(tǒng)通過委派與JDBC驅(qū)動器相互作用,這是一個橋梁模式的例子。

原文筆者不認為 DriverManager 作為 Refined Abstraction 角色存在,而是視作兩個變化維度之間的一個"過渡",原本的"橋"是 Abstraction 和 Implementor 之間的組合/聚合關系,而現(xiàn)在DriverManager 類本身成為了"橋",可以看作是橋梁模式的一個變體

(5)觀點五:變化的維度一個是 Driver,一個是 Connection:

如果從觀點四的原文筆者的角度看,把 DriverManager 類本身作為"橋",那么我們還可以提出一種新的觀點,繪制類圖如下:

設計模式系列文章:

Java設計模式之創(chuàng)建型:原型模式

Java設計模式之結構型:裝飾器模式

Java設計模式之結構型:橋接模式

Java設計模式之結構型:外觀模式

Java設計模式之結構型:組合模式

Java設計模式之行為型:策略模式

Java設計模式之行為型:模板方法模式

Java設計模式之行為型:觀察者模式

Java設計模式之行為型:訪問者模式

Java設計模式之行為型:中介者模式

Java設計模式之行為型:命令模式

Java設計模式之行為型:備忘錄模式

Java設計模式之行為型:迭代器模式

Java設計模式之行為型:解釋器模式

參考博客:

JDBC和橋接模式 - 枯落 - 博客園

輕松掌握Java橋接模式

23種設計模式(9) java橋接模式

總結

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注腳本之家的更多內(nèi)容!

相關文章

  • Redisson延遲隊列執(zhí)行流程源碼解析

    Redisson延遲隊列執(zhí)行流程源碼解析

    這篇文章主要為大家介紹了Redisson延遲隊列執(zhí)行流程源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09
  • 新手入門了解ArrayList擴容機制

    新手入門了解ArrayList擴容機制

    這篇文章主要介紹了新手入門了解ArrayList擴容機制,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10
  • 理解Java注解及Spring的@Autowired是如何實現(xiàn)的

    理解Java注解及Spring的@Autowired是如何實現(xiàn)的

    今天通過本文帶領大家學習注解的基礎知識,學習Spring的@Autowired是怎么實現(xiàn)的,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-07-07
  • Tomcat?8.5?+mysql?5.7+jdk1.8開發(fā)JavaSE的金牌榜小項目

    Tomcat?8.5?+mysql?5.7+jdk1.8開發(fā)JavaSE的金牌榜小項目

    這篇文章主要介紹了Tomcat?8.5?+mysql?5.7+jdk1.8開發(fā)JavaSE的金牌榜小項目,本文通過圖文實例相結合給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • JavaWeb實現(xiàn)顯示mysql數(shù)據(jù)庫數(shù)據(jù)

    JavaWeb實現(xiàn)顯示mysql數(shù)據(jù)庫數(shù)據(jù)

    MySQL是最流行的關系型數(shù)據(jù)庫管理系統(tǒng),在WEB應用方面MySQL是最好的。本文將利用JavaWeb實現(xiàn)顯示mysql數(shù)據(jù)庫數(shù)據(jù)功能,需要的可以參考一下
    2022-03-03
  • Spring Data環(huán)境搭建實現(xiàn)過程解析

    Spring Data環(huán)境搭建實現(xiàn)過程解析

    這篇文章主要介紹了Spring Data環(huán)境搭建實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • Java中的System類、BigInteger類和BigDecimal類詳解

    Java中的System類、BigInteger類和BigDecimal類詳解

    這篇文章主要介紹了Java中的System類、BigInteger類和BigDecimal類詳解,arraycopy()方法,復制數(shù)組元素,比較適合底層調(diào)用,一般使用Arrays.copyOf()完成復制數(shù)組,需要的朋友可以參考下
    2023-09-09
  • 常用的ResponseEntity.BodyBuilder和自定義ResponseEntity的實例

    常用的ResponseEntity.BodyBuilder和自定義ResponseEntity的實例

    這篇文章主要介紹了常用的ResponseEntity.BodyBuilder和自定義ResponseEntity的實例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • java實現(xiàn)2048小游戲(含注釋)

    java實現(xiàn)2048小游戲(含注釋)

    這篇文章主要為大家介紹了java實現(xiàn)2048小游戲,含詳細注釋,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • SpringCloud配置刷新原理解析

    SpringCloud配置刷新原理解析

    這篇文章主要介紹了SpringCloud之配置刷新的原理,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-05-05

最新評論