1. 程式人生 > 實用技巧 >【設計模式(七)】結構型模式之橋接模式

【設計模式(七)】結構型模式之橋接模式

個人學習筆記分享,當前能力有限,請勿貶低,菜鳥互學,大佬繞道

如有勘誤,歡迎指出和討論,本文後期也會進行修正和補充


前言

設想如果要繪製矩形、圓形、橢圓、正方形4個形狀,且各有紅、黃、藍3種顏色,那麼顯然一共有12種不同的結果

如果有m個形狀,n個顏色,那麼需要定義m*n個類,看上去可以接受是嗎?

那如果要新增一種顏色,就得多定義n個類,同理增加一種形狀也需要增加m個類,修改的話同理也要修改大量的類

這個維護成本可就高的過分了,耦合度太高,而且違背了單一職責原則,那咋辦嘛?

換個思路,其實可以將形狀與顏色分離開,再將其將其進行組合,即可得到需要的結果

這樣一來,形狀和顏色從繼承關係變成了關聯關係,因此將可以獨立變化,互不影響

,那麼新增形狀或顏色都只需要增加一個類,變更也只需要修改一個類

萬事分個主次,我們不妨將形狀為主,顏色為次,顏色作為形狀的一種屬性

同理,形狀也可以擁有其它屬性,比如漸變度、透明度、邊框等等,都可以用橋接模式組合在一起,且獨立變化


橋接(Bridge)是用於把抽象化與實現化解耦,使得二者可以獨立變化。這種型別的設計模式屬於結構型模式,它通過提供抽象化和實現化之間的橋接結構,來實現二者的解耦。

這種模式涉及到一個作為橋接的介面,使得實體類的功能獨立於介面實現類。這兩種型別的類可被結構化改變而互不影響。


1.介紹

使用目的:將抽象部分與它的實現部分分離開來,使他們都可以獨立變化

使用時機:實現系統可能有多個角度分類,每一種角度都可能變化,

解決問題:在有多種可能會變化的情況下,用繼承會造成類爆炸問題,擴充套件起來不靈活。

實現方法:把這種多角度分類分離出來,讓它們獨立變化,減少它們之間耦合

應用例項

  1. 奶茶會有主材、溫度、配料等多個獨立的選項,互不影響
  2. Timer().schedule(new TimerTask(){}),需要傳入一個TimerTask物件,我們可以對其進行自定義,只要保持物件的類繼承TimerTask就行了

優點

  1. 抽象和實現的分離。
  2. 優秀的擴充套件能力。
  3. 實現細節對客戶透明。

缺點

  1. 提高了系統的抽象程度,也就一定程度上增加系統複雜度
  2. 由於聚合關聯關係建立在抽象層,開發者需要針對抽象進行設計與程式設計
  3. 橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用範圍具有一定的侷限性。

簡而言之,就是避免繼承關係,轉而建立關聯關係,進而脫耦,再進行組合


概念補充

鑑於出現了一些較為抽象的概念,這裡進行一下補充解釋

  • 抽象化:將複雜物體的一個或幾個特性抽出去而只注意其他特性的行動或過程。在面向物件就是將物件共同的性質抽取出去而形成類的過程

    比如在前言中,我們將顏色抽離出去,而只在意形狀,也就是將顏色抽象化了

  • 實現化:針對抽象化給出的具體實現。它和抽象化是一個互逆的過程,實現化是對抽象化事物的進一步具體化。

    雖然將顏色抽離出去了,但是每種顏色依然需要實現,生成自己類,也就是將顏色實現化

  • 脫耦:脫耦就是將抽象化和實現化之間的耦合解脫開,或者說是將它們之間的強關聯改換成弱關聯,將兩個角色之間的繼承關係改為關聯關係

    我們將顏色和形狀分離開了,使得兩者可以獨立變化,只需要保證能對接上即可,也就是將顏色與形狀脫耦

橋接模式中的所謂脫耦,就是指在一個軟體系統的抽象化和實現化之間使用關聯關係(組合或者聚合關係)而不是繼承關係,從而使兩者可以相對獨立地變化,這就是橋接模式的用意。


2.結構

橋接模式通常包括4個主要角色

  • 抽象化(Abstraction)角色:定義抽象類,幷包含一個對實現化物件的引用。
  • 擴充套件抽象化(Refined Abstraction)角色:是抽象化角色的子類,實現父類中的業務方法,並通過組合關係調用實現化角色中的業務方法。
  • 實現化(Implementor)角色:定義實現化角色的介面,供擴充套件抽象化角色呼叫。
  • 具體實現化(Concrete Implementor)角色:給出實現化角色介面的具體實現。

  • 客戶端呼叫抽象類Shape(抽象化角色)
    • 抽象類Shape持有介面類ColorBorder,作為其兩項屬性(實現化角色)
      • 實體類BlueRed實現Color,作為具體的顏色屬性(具體實現化角色)
      • 實體類NormalBorder實現Border,作為具體的邊框屬性(具體實現化角色)
    • 實體類CircleSquareRectangle繼承Shape,並實現抽象方法,作為具體的實體(擴充套件抽象化角色)

Shape、Color、Border自身均無法例項化,我們需要例項化各個具體屬性實體,並組裝在一起,進而構成一個整體


3.實現

模擬業務如下:

  • 需要目標角色包括兩個屬性,顏色Color和形狀Shape,並擁有方法draw()輸出當前角色資訊
  • 顏色已有兩種RedBlue
  • 形狀已有兩種CircleSquare

我們將Shape作為抽象化角色,Color作為實現化角色

實際應用中根據需求角色哪種屬性作為抽象化角色,其餘屬性作為實現化角色

  1. 定義介面Color(實現化角色)

    interface Color {
        String drawColor();
    }
    
  2. 定義類RedBlue,實現Color(具體實現化角色)

    class Red implements Color {
        @Override
        public String drawColor() {
            return "red";
        }
    }
    
    class Blue implements Color {
        @Override
        public String drawColor() {
            return "blue";
        }
    }
    
  3. 定義抽象類Shape(抽象化角色)

    abstract class Shape {
        protected Color color;
    
        public Shape(Color color) {
            this.color = color;
        }
    
        abstract void draw();
    }
    

    請注意,這裡使用建構函式引用color,也可以使用別的方法,如提供setShape(Color color)方法等均可

  4. 定義類CircleSquare(擴充套件抽象化角色)

    class Circle extends Shape {
    
        public Circle(Color color) {
            super(color);
        }
    
        @Override
        void draw() {
            System.out.println("draw a circle with " + color.drawColor());
        }
    }
    
    class Square extends Shape {
    
        public Square(Color color) {
            super(color);
        }
    
        @Override
        void draw() {
            System.out.println("draw a square with " + color.drawColor());
        }
    }
    

客戶端呼叫

public class BridgeTest {
    public static void main(String[] args) {
        Shape redCircle = new Circle(new Red());
        redCircle.draw();

        Shape blueSquare = new Square(new Blue());
        blueSquare.draw();
    }

}

執行結果

4.擴充套件使用

橋接模式與介面卡模式的聯用

橋接模式可以將多種屬性組裝在一起,分離為抽象化角色和實現化角色,那如果無法相容呢?

比如呼叫了大量第三方介面,甚至是開發者之間未提前約定好介面,都會出現不相容的情況

這個時候就可以使用介面卡模式,對介面進行轉換,使其能夠相容,進而在一起協同工作

在開發過程中,也可以使用預設介面卡來規範介面,暫未實現的可以預設


後記

橋接模式的核心思想就是使用關聯關係替換繼承關係,從而將一個整體分成不同的元件,而不是不同層級

好處是脫耦,便於擴充套件和維護

這種思想才是我們學習的重點,能幫助我們寫出更優質的程式碼,而不僅僅是個程式碼的搬運工而已


作者:Echo_Ye

WX:Echo_YeZ

Email :[email protected]

個人站點:在搭了在搭了。。。(右鍵 - 新建資料夾)