1. 概述
橋接模式(Bridge Pattern)是一種結構型設計模式。在理解橋接模式前债蜜,我們要先能夠區(qū)分“類的功能層次結構”和“類的實現(xiàn)層次結構”。
舉一個簡單的例子,比如我們設計了一個程序置逻,它有打印字符串的功能,同時它又需要分別能夠在 windows 和 linux 上運行备绽,并且打印不同的內(nèi)容券坞。那么假定我們有一個 Program 類,類中有一個print方法肺素,那么我們會在 ProgramWinImpl 和 ProgramLiunxImpl 中分別實現(xiàn) print 方法用于打印不同的內(nèi)容恨锚,這就是我們上面說到的“類的實現(xiàn)層次結構”的拓展。假定現(xiàn)在我們需要給這個程序增加一個新功能 multiPrint倍靡,用于打印多行字符串猴伶,那么我們就會創(chuàng)建一個 MutilProgram 來繼承 Program,并且增加 multiPrint 這個方法菌瘫。這就是我們上面說到的“類的功能層次結構”的拓展蜗顽。如果對這兩種不同維度的拓展都使用簡單的繼承思想,那么我們的繼承關系將會非秤耆茫混雜、難以理解忿等。這時栖忠,我們就需要引入橋接模式,幫助我們搭建“類的功能層次結構”和“類的實現(xiàn)層次結構”之間的橋梁贸街。
2. 模式類圖
3. 模式角色
Abstraction (抽象化)
Abstraction 角色位于“類的功能層次結構”的最上層庵寞。該角色保存了Implementor角色的實例,使用Implementor角色的方法定義基本功能薛匪。
RefinedAbstraction (改善的抽象化)
RefinedAbstraction 角色負責在基礎上增加新的功能捐川。
Implementor (實現(xiàn)者)
Implementor 角色位于“類的實現(xiàn)層次結構”的最上層。它定義了用于實現(xiàn) Abstraction 角色的接口的方法逸尖。
ConcreteImplementor (具體實現(xiàn)者)
ConcreteImplementor 角色負責實現(xiàn) Implementor 角色中定義的方法古沥。
4. 代碼示例
類的功能層次結構
Display.java
Display 類是“類的功能層次結構”的最上層瘸右,表示功能的抽象。它的 impl 字段保存了實現(xiàn) Display 類的具體功能的實例岩齿。該實例通過 Display 的構造函數(shù)被傳遞給 Display 類太颤,保存在 impl 字段中。impl 字段就是類的兩個層次結構的“橋梁”盹沈。
public class Display {
private DisplayImpl impl;
public Display(DisplayImpl impl) {
this.impl = impl;
}
public void open() {
this.impl.rawOpen();
}
public void print() {
this.impl.rawPrint();
}
public void close() {
this.impl.rawClose();
}
public void display() {
open();
print();
close();
}
}
CountDisplay.java
CountDisplay 類是 Display 類的功能層次結構的拓展龄章,它增加了“多次顯示”的功能。
public class CountDisplay extends Display {
public CountDisplay(DisplayImpl impl) {
super(impl);
}
public void multiDisplay(int times) {
open();
for (int i = 0; i < times; i++) {
print();
}
close();
}
}
類的實現(xiàn)層次結構
DisplayImpl.java
DisplayImpl 是一個抽象類乞封,只聲明的對應 Display 類的三個抽象方法做裙。
public abstract class DisplayImpl {
public abstract void rawOpen();
public abstract void rawPrint();
public abstract void rawClose();
}
StringDisplayImpl.java
StringDisplayImpl 類最后實現(xiàn)了 Display 的所有功能。
public class StringDisplayImpl extends DisplayImpl {
private String string;
private int width;
public StringDisplayImpl(String string) {
this.string = string;
this.width = string.getBytes().length;
}
@Override
public void rawOpen() {
printLine();
}
@Override
public void rawPrint() {
System.out.println("|" + string + "|");
}
@Override
public void rawClose() {
printLine();
}
private void printLine() {
System.out.print("+");
for (int i = 0; i < width; i++) {
System.out.print("-");
}
System.out.println("+");
}
}
Main.java
最后我們看一下如何調用 Display肃晚。
public class Main {
public static void main(String[] args){
Display d1 = new Display(new StringDisplayImpl("hello world"));
CountDisplay d2 = new CountDisplay(new StringDisplayImpl("hello world"));
d1.display();
d2.display();
d2.multiDisplay(5);
}
}
結果
+-----------+
|hello world|
+-----------+
+-----------+
|hello world|
+-----------+
+-----------+
|hello world|
|hello world|
|hello world|
|hello world|
|hello world|
+-----------+
5. 延展閱讀
繼承是強關聯(lián)锚贱,委托是弱關聯(lián)
繼承是一種拓展類的有效手段,但是其弊端就是使父類和子類之間有很強的關聯(lián)性陷揪。如果我們想靈活的改變類之間的關系惋鸥,那么使用“委托”的概念就會顯得更合適。
以我們的代碼示例為例悍缠,所謂“委托”卦绣,就是指 Display 類自身的方法并不自己直接處理邏輯,而是交由(委托) DisplayImpl 實現(xiàn)類來處理飞蚓。
public void open() {
this.impl.rawOpen();
}
而 DisplayImpl 類實在 Display 類的實例生成時才被作為參數(shù)傳入的滤港,所以 Display 類中方法的最終實現(xiàn)可以在此刻才被決定。這就是通過“委托”實現(xiàn)類功能的自由拓展趴拧。