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

詳解Java設(shè)計(jì)模式之橋接模式

 更新時(shí)間:2022年06月23日 11:26:16   作者:程序員小徐同學(xué)  
橋接,顧名思義,就是用來(lái)連接兩個(gè)部分,使得兩個(gè)部分可以互相通訊。橋接模式將系統(tǒng)的抽象部分與實(shí)現(xiàn)部分分離解耦,使他們可以獨(dú)立的變化。本文通過(guò)示例詳細(xì)介紹了橋接模式的原理與使用,需要的可以參考一下

一、什么是橋接模式:

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

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

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

所以,橋接模式一般適用于以下幾種應(yīng)用場(chǎng)景:

(1) 系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個(gè)層次之間建立靜態(tài)的繼承聯(lián)系,則可以通過(guò)橋接模式使他們?cè)诔橄髮咏⒁粋€(gè)關(guān)聯(lián)關(guān)系;

(2) 系統(tǒng)不希望使用繼承或因?yàn)槎鄬哟卫^承導(dǎo)致系統(tǒng)類的個(gè)數(shù)急劇增加時(shí)

(3) 一個(gè)類存在兩個(gè)獨(dú)立變化的維度,而這兩個(gè)維度都需要進(jìn)行擴(kuò)展。

二、UML結(jié)構(gòu)圖

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

三、代碼實(shí)現(xiàn)

Implementor 接口類:

public interface Implementor {
    void operationImpl();
}

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

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

Abstraction 抽象類:

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

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

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

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

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

Java 中,我們使用 JDBC 連接數(shù)據(jù)庫(kù)時(shí),在各個(gè)數(shù)據(jù)庫(kù)之間進(jìn)行切換,基本不需要?jiǎng)犹嗟拇a,原因就是使用了橋接模式,JDBC 提供統(tǒng)一接口,每種類型的數(shù)據(jù)庫(kù)提供各自的實(shí)現(xiàn),然后由橋接類創(chuàng)建一個(gè)連接數(shù)據(jù)庫(kù)的驅(qū)動(dòng),使用某一個(gè)數(shù)據(jù)庫(kù)的時(shí)候只需要切換一下就行。接下來(lái)我們就對(duì) JDBC 的源碼做下剖析:

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

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

短短兩行代碼難以看出橋接模式的結(jié)構(gòu),下面先對(duì)源碼進(jìn)行一定的分析,理解各個(gè)類和接口之間的關(guān)系:

1、源碼分析

(1)Class.forName() 方法:

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

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

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

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

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)字段的類型是實(shí)現(xiàn)了 List 接口的 CopyOnWriteArrayList 類,它能夠保存進(jìn)一步封裝 java.sql.Driver 接口的 DriverInfo 類實(shí)例,DriverInfo 類的聲明代碼如下:

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

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

(3)DriverManager 類:

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

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() 方法會(huì)遍歷 registeredDrivers 靜態(tài)字段,獲取字段內(nèi)保存的每一個(gè) Driver 來(lái)嘗試響應(yīng)客戶端的數(shù)據(jù)庫(kù)連接請(qǐng)求,若所有 Driver 都連接數(shù)據(jù)庫(kù)失敗,則提示連接失敗信息

(4)Connection接口

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

2、源碼類

對(duì) Driver 和 Connection 進(jìn)行抽象

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

但是,和 Driver 接口不同的是,Connection 接口與 DriverManager 類的關(guān)系只是聯(lián)系較弱的依賴關(guān)系,并不符合橋接模式的定義和特點(diǎn)。

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

3、對(duì) JDBC 的觀點(diǎn)

(1)觀點(diǎn):JDBC采用的是策略模式而不是橋接模式

jdbc是橋接模式還是策略模式?

因?yàn)檫@確實(shí)和策略模式十分相似,如果把橋接模式的抽象部分簡(jiǎn)化來(lái)看,不去設(shè)計(jì)Abstraction,也就是用 Refined Abstraction 代替 Abstraction,那么就類似于策略模式的 Context 來(lái)使用接口的對(duì)象。

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

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

以上就是詳解Java設(shè)計(jì)模式之橋接模式的詳細(xì)內(nèi)容,更多關(guān)于Java橋接模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • mybatis對(duì)于list更新sql語(yǔ)句的寫法說(shuō)明

    mybatis對(duì)于list更新sql語(yǔ)句的寫法說(shuō)明

    這篇文章主要介紹了mybatis對(duì)于list更新sql語(yǔ)句的寫法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • SpringBoot?快速實(shí)現(xiàn)分庫(kù)分表的2種方式

    SpringBoot?快速實(shí)現(xiàn)分庫(kù)分表的2種方式

    本文將為您介紹?ShardingSphere?的一些基礎(chǔ)特性和架構(gòu)組成,以及在?Springboot?環(huán)境下通過(guò)JAVA編碼和Yml配置兩種方式快速實(shí)現(xiàn)分庫(kù)分表功能,感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • Spring?Boot?整合RocketMq實(shí)現(xiàn)消息過(guò)濾功能

    Spring?Boot?整合RocketMq實(shí)現(xiàn)消息過(guò)濾功能

    這篇文章主要介紹了Spring?Boot?整合RocketMq實(shí)現(xiàn)消息過(guò)濾,本文講解了RocketMQ實(shí)現(xiàn)消息過(guò)濾,針對(duì)不同的業(yè)務(wù)場(chǎng)景選擇合適的方案即可,需要的朋友可以參考下
    2022-06-06
  • SpringAOP如何修改請(qǐng)求參數(shù)列表

    SpringAOP如何修改請(qǐng)求參數(shù)列表

    這篇文章主要介紹了SpringAOP如何修改請(qǐng)求參數(shù)列表問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 關(guān)于idea中ssm框架的編碼問(wèn)題分析

    關(guān)于idea中ssm框架的編碼問(wèn)題分析

    在實(shí)際開發(fā)中需要將操作系統(tǒng)編碼、文件編碼、頁(yè)面編碼以及tomcat服務(wù)器編碼保持一致,而tomcat在默認(rèn)情況下是使用UTF-8,這就使得其打印的日志文件出現(xiàn)中文亂碼,因此在一般情況下,只需要將tomcat服務(wù)器的編碼改為GBK即可
    2021-06-06
  • Java中Minio的基本使用詳解

    Java中Minio的基本使用詳解

    這篇文章主要介紹了Java中Minio的基本使用詳解,MinIO 是一個(gè)基于Apache License v2.0開源協(xié)議的對(duì)象存儲(chǔ)服務(wù),它兼容亞馬遜S3云存儲(chǔ)服務(wù)接口,非常適合于存儲(chǔ)大容量非結(jié)構(gòu)化的數(shù)據(jù),例如圖片、視頻、日志文件、備份數(shù)據(jù)和容器/虛擬機(jī)鏡像等,需要的朋友可以參考下
    2024-01-01
  • java基于反射得到對(duì)象屬性值的方法

    java基于反射得到對(duì)象屬性值的方法

    這篇文章主要介紹了java基于反射得到對(duì)象屬性值的方法,結(jié)合實(shí)例形式分析了java基于反射獲取對(duì)象屬性值的相關(guān)實(shí)現(xiàn)方法與操作技巧,需要的朋友可以參考下
    2017-03-03
  • Java刪除文件、目錄及目錄下所有文件的方法實(shí)例

    Java刪除文件、目錄及目錄下所有文件的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于利用Java刪除文件、目錄及目錄下所有文件的方法,文中給出了詳細(xì)的示例代碼與注解,有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2016-12-12
  • Mybatis-plus?sql注入及防止sql注入詳解

    Mybatis-plus?sql注入及防止sql注入詳解

    mybatis-plus提供了許多默認(rèn)單表 CRUD 語(yǔ)句,對(duì)于其他SQL情況愛(ài)莫能助,下面這篇文章主要給大家介紹了關(guān)于Mybatis-plus?sql注入及防止sql注入的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-10-10
  • Java實(shí)現(xiàn)導(dǎo)出pdf格式文件的示例代碼

    Java實(shí)現(xiàn)導(dǎo)出pdf格式文件的示例代碼

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)導(dǎo)出pdf格式文件的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02

最新評(píng)論