【設計模式系列16】橋接模式原理及範例分析

2020-10-06 11:00:06

前言

本文主要介紹橋接模式的原理,並會結合範例進行分析。橋接模式其實和組合有點相似,橋接模式也是通過組合來實現的,但是橋接模式和組合模式的側重點不一樣,接下來就讓我們一起來看看橋接模式。

什麼是橋接模式

橋接模式(Bridge Pattern)也稱之為橋樑模式,介面(Interface)模式或者柄體(Handle and Body)模式。

橋接模式是將抽象部分與它的實現部分分離,使它們都可以獨立的變化。橋接模式屬於結構型模式。

橋接模式的主要目的是通過組合的方式建立兩個類之間的關係,而並不通過繼承來實現,橋接模式的核心在於解耦抽象和實現。

好了,裝逼時刻到了:Talk is cheap,Show you the code,先看一個非常簡單的例子。

橋接模式範例

下面我們以發訊息為例來進行說明,首先訊息型別是一個維度,比如可以發郵件,傳簡訊。然後訊息可以有緊急訊息,普通訊息,這又是一個具體的維度。

1、首先新建一個訊息介面類:

package com.zwx.design.pattern.bridge;

public interface IMessage {
    void send(String content,String toUser);
}

2、新建兩個實現類,分別是郵件訊息和簡訊訊息:

package com.zwx.design.pattern.bridge;

public class EmailMessage implements IMessage {
    @Override
    public void send(String content, String toUser) {
        System.out.println(String.format("郵件訊息->%s:%s",toUser,content));
    }
}
package com.zwx.design.pattern.bridge;

public class SmsMessage implements IMessage {
    @Override
    public void send(String content, String toUser) {
        System.out.println(String.format("SMS訊息->%s:%s",toUser,content));
    }
}

假如這時候我們需要按照普通訊息和緊急訊息來做一些不同的事情,那麼這時候普通寫法會怎麼寫,我想可能會是如下寫法,直接改寫訊息類,在分別去實現緊急訊息類和普通訊息類:

public class SmsMessage extends CommonMsg implements IMessage {

但是Java是單繼承,所以一次只能繼承一個,要麼就把普通訊息和緊急訊息設定為介面,要麼就作為組合的形式,將緊急訊息和普通訊息分別作為屬性存到對應的訊息型別裡面去。但是不論是哪種形式,都需要修改原先的SmsMessage 類。

所以這時候就需要使用橋接模式,將抽象(訊息型別)與實現(訊息緊急程度)進行分離。

3、新建一個抽象類,將IMessage整合進去:

package com.zwx.design.pattern.bridge;

public abstract class AbstractMessage {
    private IMessage iMessage;

    public AbstractMessage(IMessage iMessage) {
        this.iMessage = iMessage;
    }

    public void sendMessage(String content,String toUser){
        this.iMessage.send(content,toUser);
    }
}

4、新建一個緊急程度為普通的訊息類:

package com.zwx.design.pattern.bridge;

public class CommonMsg extends AbstractMessage {
    public CommonMsg(IMessage iMessage) {
        super(iMessage);
    }

    @Override
    public void sendMessage(String content, String toUser) {
        this.doSomething();
        super.sendMessage(content, toUser);
    }

    private void doSomething() {
        System.out.println("這只是一個普通訊息");
    }
}

5、新建一個緊急程度為緊急的訊息類:

package com.zwx.design.pattern.bridge;

public class UrgentMessage extends AbstractMessage{
    public UrgentMessage(IMessage iMessage) {
        super(iMessage);
    }

    @Override
    public void sendMessage(String content, String toUser) {
        doSomething();
        super.sendMessage(content, toUser);
    }

    private void doSomething() {
        System.out.println("這是緊急訊息,請優先傳送");
    }
}

這時候假如要新增其他緊急程度那直接再建一個類就好了,非常方便。

6、最後新建一個測試類來測試一下:

package com.zwx.design.pattern.bridge;

import java.io.IOException;

public class TestBridge {
    public static void main(String[] args) throws IOException {
        IMessage iMessage = new EmailMessage();
        AbstractMessage abstractMessage = new UrgentMessage(iMessage);//緊急郵件訊息
        abstractMessage.sendMessage("您好","張三丰");
        //再來一個普通郵件訊息
        System.out.println("------------分割線---------------");
        abstractMessage = new CommonMsg(iMessage);
        abstractMessage.sendMessage("您好","郭靖");
    }
}

輸出結果如下:

這是緊急訊息,請優先傳送
郵件訊息->張三丰:您好
------------分割線---------------
這只是一個普通訊息
郵件訊息->郭靖:您好

橋接模式角色分類

從上面的範例中我們可以得出橋接模式有以下4個角色:

  • 抽象(Abstraction)角色:一般為抽象類。該類持有一個實現角色的參照,並通過構造方法傳入一個具體的實現類(如範例中的AbstractMessage)。
  • 修正抽象(RefinedAbstraction)角色:擴充套件抽象角色,可以對抽象角色的方法進行覆蓋重寫來達到完善的目的(如範例中的UrgentMessage和CommonMsg)。
  • 實現(Implementor)角色:定義一個維度的基本操作,提供給抽象角色使用,該類一般為介面或者抽象類(如範例中的IMessage)。
  • 具體實現(ConcreteImplementor)角色:Implementor的具體實現類(如範例中的EmailMessage和SmsMessage)。

橋接模式應用場景

當一個類內部具有兩種或者多種緯度變化時,使用橋接模式可以解耦這些維度,使得高層程式碼結構穩定,橋接模式一般適用於以下場景:

  • 1、在抽象和具體之間需要增加更多靈活性的場景。
  • 2、一個類存在2個或者以上獨立變化的維度,而這些維度又需要獨立進行擴充套件時。
  • 3、不希望使用繼承,或因為多層繼承導致類的個數劇增時可以考慮使用橋接模式

PS:橋接模式的其中一個目的就是為了替換繼承

橋接模式優缺點

優點:
1、分離抽象部分及其實現部分
2、提高了系統的擴充套件性
3、符合開閉原則
4、符合合成複用原則

缺點:
1、增加了系統的理解難度和設計難度(這也算是大部分設計模式的共性)
2、需要正確識別系統中各個獨立變化的維度

總結

本文主要介紹橋接模式的原理,並結合了範例對其進行了分析。橋接模式也是通過組合來實現的。我們再開發中大家都知道要解耦,解耦的實質就是減少物件之間的關聯,而繼承是一種強關聯,因為一旦通過繼承,那麼子類就會擁有父類別所有公開的方法和屬性,有些可能並不是子類需要的,而組合就不一樣,組合是一種弱關聯,我只是持有一個物件,但是我持有物件所擁有的功能並不是我的,和我並沒有很強烈的關係。所以實質上在很多場景我們都可以通過組合來解耦繼承物件之間的強關聯關係。

最後還是希望大家記住程式設計中的一條原則,那就是:多用組合,少用繼承

請關注我,和孤狼一起學習進步