国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

橋接模式:如何實(shí)現(xiàn)支持不同類型和渠道的消息推送系統(tǒng)?

這篇具有很好參考價(jià)值的文章主要介紹了橋接模式:如何實(shí)現(xiàn)支持不同類型和渠道的消息推送系統(tǒng)?。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

????????上一節(jié)課我們學(xué)習(xí)了第一種結(jié)構(gòu)型模式:代理模式。它在不改變?cè)碱悾ɑ蛘呓斜淮眍悾┐a的情況下,通過(guò)引入代理類來(lái)給原始類附加功能。代理模式在平時(shí)的開(kāi)發(fā)經(jīng)常被用到,常用在業(yè)務(wù)系統(tǒng)中開(kāi)發(fā)一些非功能性需求,比如:監(jiān)控、統(tǒng)計(jì)、鑒權(quán)、限流、事務(wù)、冪等、日志。

????????今天,我們?cè)賹W(xué)習(xí)另外一種結(jié)構(gòu)型模式:橋接模式。橋接模式的代碼實(shí)現(xiàn)非常簡(jiǎn)單,但是理解起來(lái)稍微有點(diǎn)難度,并且應(yīng)用場(chǎng)景也比較局限,所以,相當(dāng)于代理模式來(lái)說(shuō),橋接模式在實(shí)際的項(xiàng)目中并沒(méi)有那么常用,你只需要簡(jiǎn)單了解,見(jiàn)到能認(rèn)識(shí)就可以,并不是我們學(xué)習(xí)的重點(diǎn)。

橋接模式的原理

對(duì)于這個(gè)模式有兩種不同的理解方式。

當(dāng)然,這其中“最純正”的理解方式,當(dāng)屬GoF的《設(shè)計(jì)模式》一書(shū)中對(duì)橋接模式的定義。畢竟,這23種經(jīng)典的設(shè)計(jì)模式,最初就是由這本書(shū)總結(jié)出來(lái)的。在GoF的《設(shè)計(jì)模式》一書(shū)中,橋接模式是這么定義的:“Decouple an abstraction from its implementation so that the two can vary independently。”翻譯成中文就是:“將抽象和實(shí)現(xiàn)解耦,讓它們可以獨(dú)立變化。”

關(guān)于橋接模式,很多書(shū)籍、資料中,還有另外一種理解方式:“一個(gè)類存在兩個(gè)(或多個(gè))獨(dú)立變化的維度,我們通過(guò)組合的方式,讓這兩個(gè)(或多個(gè))維度可以獨(dú)立進(jìn)行擴(kuò)展?!蓖ㄟ^(guò)組合關(guān)系來(lái)替代繼承關(guān)系,避免繼承層次的指數(shù)級(jí)爆炸。這種理解方式非常類似于,我們之前講過(guò)的“組合優(yōu)于繼承”設(shè)計(jì)原則,所以,這里我就不多解釋了。我們重點(diǎn)看下GoF的理解方式。

其關(guān)鍵在于避免繼承層次的指數(shù)級(jí)爆炸。

GoF給出的定義非常的簡(jiǎn)短,單憑這一句話,估計(jì)沒(méi)幾個(gè)人能看懂是什么意思。所以,我們通過(guò)JDBC驅(qū)動(dòng)的例子來(lái)解釋一下。JDBC驅(qū)動(dòng)是橋接模式的經(jīng)典應(yīng)用。我們先來(lái)看一下,如何利用JDBC驅(qū)動(dòng)來(lái)查詢數(shù)據(jù)庫(kù)。具體的代碼如下所示:?

Class.forName("com.mysql.jdbc.Driver");//加載及注冊(cè)JDBC驅(qū)動(dòng)程序
String url = "jdbc:mysql://localhost:3306/sample_db?user=root&password=your_password";
Connection con = DriverManager.getConnection(url);
Statement stmt = con.createStatement();
String query = "select * from test";
ResultSet rs=stmt.executeQuery(query);
while(rs.next()) {
  rs.getString(1);
  rs.getInt(2);
}

如果我們想要把MySQL數(shù)據(jù)庫(kù)換成Oracle數(shù)據(jù)庫(kù),只需要把第一行代碼中的com.mysql.jdbc.Driver換成oracle.jdbc.driver.OracleDriver就可以了。當(dāng)然,也有更靈活的實(shí)現(xiàn)方式,我們可以把需要加載的Driver類寫(xiě)到配置文件中,當(dāng)程序啟動(dòng)的時(shí)候,自動(dòng)從配置文件中加載,這樣在切換數(shù)據(jù)庫(kù)的時(shí)候,我們都不需要修改代碼,只需要修改配置文件就可以了。

不管是改代碼還是改配置,在項(xiàng)目中,從一個(gè)數(shù)據(jù)庫(kù)切換到另一種數(shù)據(jù)庫(kù),都只需要改動(dòng)很少的代碼,或者完全不需要改動(dòng)代碼,那如此優(yōu)雅的數(shù)據(jù)庫(kù)切換是如何實(shí)現(xiàn)的呢?

package com.mysql.jdbc;
import java.sql.SQLException;

/**
 * The Java SQL framework allows for multiple database drivers. Each driver should supply a class that implements the Driver interface
 *
 * When a Driver class is loaded, it should create an instance of itself and register it with the DriverManager. This means that a user can load and register a
 * driver by doing Class.forName("foo.bah.Driver")
 */
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    //
    // Register ourselves with the DriverManager
    //
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    /**
     * Construct a new driver and register it with DriverManager
     * 
     * @throws SQLException
     *             if a database error occurs.
     */
    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }
}

結(jié)合com.mysql.jdbc.Driver的代碼實(shí)現(xiàn),我們可以發(fā)現(xiàn),當(dāng)執(zhí)行Class.forName(“com.mysql.jdbc.Driver”)這條語(yǔ)句的時(shí)候,實(shí)際上是做了兩件事情。第一件事情是要求JVM查找并加載指定的Driver類,第二件事情是執(zhí)行該類的靜態(tài)代碼,也就是將MySQL Driver注冊(cè)到DriverManager類中。

這個(gè)也太牛了吧。直接加載類并執(zhí)行其靜態(tài)代碼塊

那么,DriverManager類是干什么用的。當(dāng)我們把具體的Driver實(shí)現(xiàn)類(比如,com.mysql.jdbc.Driver)注冊(cè)到DriverManager之后,后續(xù)所有對(duì)JDBC接口的調(diào)用,都會(huì)委派到對(duì)具體的Driver實(shí)現(xiàn)類來(lái)執(zhí)行。而Driver實(shí)現(xiàn)類都實(shí)現(xiàn)了相同的接口(java.sql.Driver ),這也是可以靈活切換Driver的原因。

?這里僅僅展示DriverManager類的一些重要屬性和方法,其他的進(jìn)行省略方便展示。

public class DriverManager {
  private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();

  //...
  static {
    loadInitialDrivers();
    println("JDBC DriverManager initialized");
  }
  //...

  public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {
    if (driver != null) {
      registeredDrivers.addIfAbsent(new DriverInfo(driver));
    } else {
      throw new NullPointerException();
    }
  }

  public static Connection getConnection(String url, String user, String password) throws SQLException {
    java.util.Properties info = new java.util.Properties();
    if (user != null) {
      info.put("user", user);
    }
    if (password != null) {
      info.put("password", password);
    }
    return (getConnection(url, info, Reflection.getCallerClass()));
  }
  //...
}

橋接模式的定義是將“抽象和實(shí)現(xiàn)解耦”,讓它們可以獨(dú)立變化。那弄懂定義中“抽象”和“實(shí)現(xiàn)”兩個(gè)概念,就是理解橋接模式的關(guān)鍵。那在JDBC這個(gè)例子中,什么是“抽象”?什么是“實(shí)現(xiàn)”呢?

實(shí)際上,JDBC本身就相當(dāng)于“抽象”。注意,這里所說(shuō)的“抽象”,指的并非“抽象類”或“接口”,而是跟具體的數(shù)據(jù)庫(kù)無(wú)關(guān)的、被抽象出來(lái)的一套“類庫(kù)”。具體的Driver(比如,com.mysql.jdbc.Driver)就相當(dāng)于“實(shí)現(xiàn)”。注意,這里所說(shuō)的“實(shí)現(xiàn)”,也并非指“接口的實(shí)現(xiàn)類”,而是跟具體數(shù)據(jù)庫(kù)相關(guān)的一套“類庫(kù)”。JDBC和Driver獨(dú)立開(kāi)發(fā),通過(guò)對(duì)象之間的組合關(guān)系,組裝在一起。JDBC的所有邏輯操作,最終都委托給Driver來(lái)執(zhí)行。

有時(shí)候,我們可以簡(jiǎn)單的理解為抽象的是接口,實(shí)現(xiàn)是接口的實(shí)現(xiàn)。

?

橋接模式:如何實(shí)現(xiàn)支持不同類型和渠道的消息推送系統(tǒng)?,設(shè)計(jì)模式,橋接模式

具體可以學(xué)習(xí):JDBC和橋接模式 - 咕~咕咕 - 博客園 (cnblogs.com)

橋接模式的應(yīng)用舉例。

API接口監(jiān)控告警的例子:根據(jù)不同的告警規(guī)則,觸發(fā)不同類型的告警。告警支持多種通知渠道,包括:郵件、短信、微信、自動(dòng)語(yǔ)音電話。通知的緊急程度有多種類型,包括:SEVERE(嚴(yán)重)、URGENCY(緊急)、NORMAL(普通)、TRIVIAL(無(wú)關(guān)緊要)。不同的緊急程度對(duì)應(yīng)不同的通知渠道。比如,SERVE(嚴(yán)重)級(jí)別的消息會(huì)通過(guò)“自動(dòng)語(yǔ)音電話”告知相關(guān)人員。

一個(gè)變化的維度是通知渠道:郵件、短信、微信和自動(dòng)語(yǔ)言電話等等

一個(gè)變化的維度是通知緊急程度:嚴(yán)重、緊急、普通和無(wú)關(guān)緊要。

在我們來(lái)一塊實(shí)現(xiàn)一下。我們先來(lái)看最簡(jiǎn)單、最直接的一種實(shí)現(xiàn)方式。代碼如下所示:

public enum NotificationEmergencyLevel {
  SEVERE, URGENCY, NORMAL, TRIVIAL
}

public class Notification {
  private List<String> emailAddresses;
  private List<String> telephones;
  private List<String> wechatIds;

  public Notification() {}

  public void setEmailAddress(List<String> emailAddress) {
    this.emailAddresses = emailAddress;
  }

  public void setTelephones(List<String> telephones) {
    this.telephones = telephones;
  }

  public void setWechatIds(List<String> wechatIds) {
    this.wechatIds = wechatIds;
  }

  public void notify(NotificationEmergencyLevel level, String message) {
    if (level.equals(NotificationEmergencyLevel.SEVERE)) {
      //...自動(dòng)語(yǔ)音電話
    } else if (level.equals(NotificationEmergencyLevel.URGENCY)) {
      //...發(fā)微信
    } else if (level.equals(NotificationEmergencyLevel.NORMAL)) {
      //...發(fā)郵件
    } else if (level.equals(NotificationEmergencyLevel.TRIVIAL)) {
      //...發(fā)郵件
    }
  }
}

//在API監(jiān)控告警的例子中,我們?nèi)缦路绞絹?lái)使用Notification類:
public class ErrorAlertHandler extends AlertHandler {
  public ErrorAlertHandler(AlertRule rule, Notification notification){
    super(rule, notification);
  }


  @Override
  public void check(ApiStatInfo apiStatInfo) {
    if (apiStatInfo.getErrorCount() > rule.getMatchedRule(apiStatInfo.getApi()).getMaxErrorCount()) {
      notification.notify(NotificationEmergencyLevel.SEVERE, "...");
    }
  }
}

針對(duì)Notification的代碼,我們將不同渠道的發(fā)送邏輯剝離出來(lái),形成獨(dú)立的消息發(fā)送類(MsgSender相關(guān)類)。其中,Notification類相當(dāng)于抽象,MsgSender類相當(dāng)于實(shí)現(xiàn),兩者可以獨(dú)立開(kāi)發(fā),通過(guò)組合關(guān)系(也就是橋梁)任意組合在一起。所謂任意組合的意思就是,不同緊急程度的消息和發(fā)送渠道之間的對(duì)應(yīng)關(guān)系,不是在代碼中固定寫(xiě)死的,我們可以動(dòng)態(tài)地去指定(比如,通過(guò)讀取配置來(lái)獲取對(duì)應(yīng)關(guān)系)。

public interface MsgSender {
  void send(String message);
}

public class TelephoneMsgSender implements MsgSender {
  private List<String> telephones;

  public TelephoneMsgSender(List<String> telephones) {
    this.telephones = telephones;
  }

  @Override
  public void send(String message) {
    //...
  }

}

public class EmailMsgSender implements MsgSender {
  // 與TelephoneMsgSender代碼結(jié)構(gòu)類似,所以省略...
}

public class WechatMsgSender implements MsgSender {
  // 與TelephoneMsgSender代碼結(jié)構(gòu)類似,所以省略...
}

public abstract class Notification {
  protected MsgSender msgSender;

  public Notification(MsgSender msgSender) {
    this.msgSender = msgSender;
  }

  public abstract void notify(String message);
}

public class SevereNotification extends Notification {
  public SevereNotification(MsgSender msgSender) {
    super(msgSender);
  }

  @Override
  public void notify(String message) {
    msgSender.send(message);
  }
}

public class UrgencyNotification extends Notification {
  // 與SevereNotification代碼結(jié)構(gòu)類似,所以省略...
}
public class NormalNotification extends Notification {
  // 與SevereNotification代碼結(jié)構(gòu)類似,所以省略...
}
public class TrivialNotification extends Notification {
  // 與SevereNotification代碼結(jié)構(gòu)類似,所以省略...
}

這樣重構(gòu)以后,就可以進(jìn)行兩個(gè)維度的擴(kuò)展,繼續(xù)增加通知渠道和通知的緊急類型。

總結(jié):橋接模式的應(yīng)用場(chǎng)景主要是針對(duì)于;一個(gè)類存在兩個(gè)(或多個(gè))獨(dú)立變化的維度,我們通過(guò)組合的方式,讓這兩個(gè)(或多個(gè))維度可以獨(dú)立進(jìn)行擴(kuò)展?!蓖ㄟ^(guò)組合關(guān)系來(lái)替代繼承關(guān)系,避免繼承層次的指數(shù)級(jí)爆炸。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-551374.html

到了這里,關(guān)于橋接模式:如何實(shí)現(xiàn)支持不同類型和渠道的消息推送系統(tǒng)?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 消息隊(duì)列——rabbitmq的不同工作模式

    消息隊(duì)列——rabbitmq的不同工作模式

    目錄 Work queues 工作隊(duì)列模式 ?Pub/Sub 訂閱模式 Routing路由模式 Topics通配符模式? ?工作模式總結(jié) C1和C2屬于競(jìng)爭(zhēng)關(guān)系,一個(gè)消息只有一個(gè)消費(fèi)者可以取到。 ?代碼部分只需要用兩個(gè)消費(fèi)者進(jìn)程監(jiān)聽(tīng)同一個(gè)隊(duì)里即可。 兩個(gè)消費(fèi)者呈現(xiàn)競(jìng)爭(zhēng)關(guān)系。 用一個(gè)生產(chǎn)者推送10條消息 兩個(gè)監(jiān)

    2024年02月16日
    瀏覽(27)
  • 枚舉類型 表示不同的 HTTP 狀態(tài)碼和相應(yīng)的錯(cuò)誤消息

    java web業(yè)務(wù)中經(jīng)常用常量來(lái)表示不同的 HTTP 響應(yīng)狀態(tài),比如 這種枚舉的使用方式允許你在代碼中使用這些常量來(lái)表示不同的 HTTP 響應(yīng)狀態(tài),而不需要硬編碼狀態(tài)碼和錯(cuò)誤消息。這提高了代碼的可讀性和可維護(hù)性,并降低了錯(cuò)誤的風(fēng)險(xiǎn),因?yàn)槟憧梢允褂眠@些常量而不是手動(dòng)輸入狀

    2024年02月08日
    瀏覽(25)
  • 嵌入式內(nèi)核鏈表list_head,如何管理不同類型節(jié)點(diǎn)的實(shí)現(xiàn)

    嵌入式內(nèi)核鏈表list_head,如何管理不同類型節(jié)點(diǎn)的實(shí)現(xiàn)

    ? ? ? ? ?在Linux內(nèi)核中,提供了一個(gè)用來(lái)創(chuàng)建雙向循環(huán)鏈表的結(jié)構(gòu) list_head。雖然linux內(nèi)核是用C語(yǔ)言寫(xiě)的,但是list_head的引入,使得內(nèi)核數(shù)據(jù)結(jié)構(gòu)也可以擁有面向?qū)ο蟮奶匦?,通過(guò)使用操作list_head 的通用接口很容易實(shí)現(xiàn)代碼的重用,有點(diǎn)類似于C++的繼承機(jī)制(希望有機(jī)會(huì)寫(xiě)篇

    2024年02月20日
    瀏覽(16)
  • Android Studio 中使用 Gradle 配置多渠道打包 配置不同的渠道名稱 配置不同的App名稱 配置不同的Logo

    Android Studio 中使用 Gradle 配置多渠道打包 配置不同的渠道名稱 配置不同的App名稱 配置不同的Logo

    三種操作都是可以混合一起用的,本來(lái)也不是很難的事情,為了方便分別理解,這里我就分開(kāi)處理了。 如果需要將打包出來(lái)的apk的名稱自動(dòng)命名成指定格式,也可以進(jìn)行配置,我這里沒(méi)這個(gè)需求,所以這里就不討論了。 另外,我的配置里面,還通過(guò)buildTypes{debug{} release{}}的方

    2024年02月09日
    瀏覽(26)
  • 橋接模式解密:跨越鴻溝,橋接抽象與實(shí)現(xiàn)

    橋接模式解密:跨越鴻溝,橋接抽象與實(shí)現(xiàn)

    橋接模式(Bridge Pattern)是一種結(jié)構(gòu)型設(shè)計(jì)模式,它將抽象部分與實(shí)現(xiàn)部分分離,使它們都可以獨(dú)?的變化。其核心思想就是解耦,在面向?qū)ο缶幊讨?,抽象和?shí)現(xiàn)是通過(guò)繼承關(guān)系來(lái)實(shí)現(xiàn)的,但這種關(guān)系是靜態(tài)的,不能在運(yùn)行時(shí)動(dòng)態(tài)改變,而橋接模式是通過(guò)組合關(guān)系來(lái)取代繼

    2024年02月08日
    瀏覽(20)
  • 如何在前端實(shí)現(xiàn)WebSocket發(fā)送和接收TCP消息(多線程模式)

    如何在前端實(shí)現(xiàn)WebSocket發(fā)送和接收TCP消息(多線程模式)

    當(dāng)在前端實(shí)現(xiàn)WebSocket發(fā)送和接收TCP消息時(shí),可以使用以下步驟來(lái)實(shí)現(xiàn)多線程模式。本文將詳細(xì)介紹如何在前端實(shí)現(xiàn)WebSocket發(fā)送和接收TCP消息,并解釋使用到的相關(guān)函數(shù)及原理。 在前端實(shí)現(xiàn)WebSocket發(fā)送和接收TCP消息的第一步是創(chuàng)建一個(gè)WebSocket連接。我們可以使用瀏覽器提供的

    2024年02月12日
    瀏覽(21)
  • 如何在前端實(shí)現(xiàn)WebSocket發(fā)送和接收UDP消息(多線程模式)

    如何在前端實(shí)現(xiàn)WebSocket發(fā)送和接收UDP消息(多線程模式)

    本文將繼續(xù)介紹如何在前端應(yīng)用中利用WebSocket技術(shù)發(fā)送和接收UDP消息,并引入多線程模式來(lái)提高發(fā)送效率和性能。我們將使用JavaScript語(yǔ)言來(lái)編寫(xiě)代碼,并結(jié)合WebSocket API、UDP數(shù)據(jù)包、Web Workers和UDP消息監(jiān)聽(tīng)器來(lái)實(shí)現(xiàn)這一功能。 首先,我們需要在前端應(yīng)用中建立一個(gè)WebSocket連接

    2024年02月12日
    瀏覽(17)
  • 如何在Java實(shí)現(xiàn)TCP方式發(fā)送和接收Socket消息(多線程模式)

    如何在Java實(shí)現(xiàn)TCP方式發(fā)送和接收Socket消息(多線程模式)

    在Java編程中,使用TCP協(xié)議進(jìn)行Socket通信是非常常見(jiàn)的場(chǎng)景。本文將詳細(xì)介紹如何在Java中實(shí)現(xiàn)TCP方式發(fā)送和接收Socket消息,并且利用多線程模式來(lái)提高通信效率。 首先,我們需要?jiǎng)?chuàng)建一個(gè)Server端來(lái)處理接收到的Socket連接請(qǐng)求。以下是實(shí)現(xiàn)的步驟: 創(chuàng)建一個(gè)ServerSocket對(duì)象,并指

    2024年02月12日
    瀏覽(21)
  • 篇七:橋接模式:連接抽象和實(shí)現(xiàn)

    篇七: “橋接模式:連接抽象和實(shí)現(xiàn)” 開(kāi)始本篇文章之前先推薦一個(gè)好用的學(xué)習(xí)工具,AIRIght,借助于AI助手工具,學(xué)習(xí)事半功倍。歡迎訪問(wèn):http://airight.fun/。 另外有2本不錯(cuò)的關(guān)于設(shè)計(jì)模式的資料,分享出來(lái)與大家學(xué)習(xí)參考。 鏈接:https://pan.baidu.com/s/1RmhQF_o1CdK8U7s5KeILog?pwd

    2024年02月13日
    瀏覽(26)
  • 橋接模式——連接抽象維度和實(shí)現(xiàn)維度

    橋接模式——連接抽象維度和實(shí)現(xiàn)維度

    橋接模式,是將抽象部分與它的具體實(shí)現(xiàn)部分分離,使它們都可以獨(dú)立地變化。它是將兩個(gè)不同的維度建立聯(lián)系。這兩個(gè)維度通常是指:抽象維度和實(shí)現(xiàn)維度。 在抽象和具體實(shí)現(xiàn)之間需要增加更多的靈活性的場(chǎng)景。 一個(gè)類存在兩個(gè)(或多個(gè))獨(dú)立變化的維度,而這兩個(gè)(或

    2024年02月17日
    瀏覽(19)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包