橋接模式
橋接模式(Bridge),將抽象部分和它的實現部分分離,使它們都可以獨立地變化。
橋接模式基於類的最小設計原則,通過使用封裝、聚合及繼承等行爲讓不同的類承擔不同的職責。它的主要特點是把抽象與行爲實現分離開來,從而可以保持各部分的獨立性以及應對它們的功能擴展。
也就是說,實現系統可能有多種方式分類,每一種分類都有可能變化。橋接模式的核心意圖就是把這些分類獨立出來,讓它們各自獨立變化,減少它們之間的耦合。
橋接模式解析
角色介紹
- Abstraction:維護了 Implementor 類,兩者是聚合關係,Abstraction 充當橋接類。
- RefinedAbstraction:是 Abstraction 抽象類的子類。
- Implementor:行爲實現類的接口。
- ConcreteImplementorA/ConcreteImplementorA:行爲的具體實現類。
橋接模式基本代碼
- Abstraction 類
public abstract class Abstraction {
private Implementor implementor;
public Abstraction(Implementor implementor) {
this.implementor = implementor;
}
protected void operation() {
implementor.operation();
}
}
- RefinedAbstraction 類
public class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor implementor) {
super(implementor);
}
@Override
protected void operation() {
super.operation();
}
}
- Implementor 類
public interface Implementor {
void operation();
}
- ConcreteImplementorA 類
public class ConcreteImplementorA implements Implementor {
@Override
public void operation() {
System.out.println("具體實現 A 的方法執行");
}
}
- ConcreteImplementorB 類
public class ConcreteImplementorB implements Implementor {
@Override
public void operation() {
System.out.println("具體實現 B 的方法執行");
}
}
- Main 類
public class Main {
public static void main(String[] args) {
Implementor implementorA = new ConcreteImplementorA();
Abstraction refinedAbstractionA = new RefinedAbstraction(implementorA);
refinedAbstractionA.operation();
Implementor implementorB = new ConcreteImplementorB();
Abstraction refinedAbstractionB = new RefinedAbstraction(implementorB);
refinedAbstractionB.operation();
}
}
示例
手機操作問題,對不同品牌手機的不同軟件功能進行編程,如通訊錄、手機遊戲等。
傳統方法
-
結構圖
-
手機類
/**
* AbstractHandset
*/
public abstract class AbstractHandset {
public abstract void run();
}
- 手機品牌 M 和手機品牌 N 類
/**
* HandsetM
*/
public abstract class HandsetM extends AbstractHandset {
}
/**
* HandsetN
*/
public abstract class HandsetN extends AbstractHandset {
}
- 手機遊戲類和手機 MP3 類
/**
* HandsetMGame
*/
public class HandsetMGame extends HandsetM {
@Override
public void run() {
System.out.println("運行 M 品牌手機的遊戲");
}
}
/**
* HandsetNGame
*/
public class HandsetNGame extends HandsetN {
@Override
public void run() {
System.out.println("運行 N 品牌手機的遊戲");
}
}
/**
* HandsetMMP3
*/
public class HandsetMMP3 extends HandsetM {
@Override
public void run() {
System.out.println("運行 M 品牌手機的 MP3");
}
}
/**
* HandsetNMP3
*/
public class HandsetNMP3 extends HandsetN {
@Override
public void run() {
System.out.println("運行 N 品牌手機的 MP3");
}
}
- Main 類
/**
* Main
*/
public class Main {
public static void main(String[] args) {
HandsetM handsetM = new HandsetMGame();
handsetM.run();
HandsetN handsetN = new HandsetNMP3();
handsetN.run();
}
}
傳統方法使用多層繼承的方案,在擴展上存在類爆炸的問題。當我們要給每個品牌的手機增加一個新功能時,就要在每個品牌的手機下面增加一個子類,這樣增加了代碼維護的成本。
事實上,很多情況下使用繼承會帶來麻煩。對象的繼承關係是在編譯時就定義好了的,所以無法在運行時改變從父類繼承的實現。子類的實現與它的父類有非常緊密的依賴關係,以至於父類實現中的任何變化必然導致其子類發生變化。當需要複用子類時,如果繼承下來的實現不適合解決新的問題,則父類必須重寫或被其他更適合的類替換。這種依賴關係限制了靈活性並最終限制複用。
使用橋接模式改進
- 結構圖
- 手機軟件類
/**
* HandsetSoft
*/
public interface HandsetSoft {
void run();
}
- 手機功能等具體類
/**
* HandsetGame
*/
public class HandsetGame implements HandsetSoft {
@Override
public void run() {
System.out.println("運行手機遊戲");
}
}
/**
* HandsetMP3
*/
public class HandsetMP3 implements HandsetSoft {
@Override
public void run() {
System.out.println("運行手機 MP3");
}
}
- 手機類
/**
* AbstractHandset
*/
public abstract class AbstractHandset {
protected HandsetSoft handsetSoft;
public AbstractHandset(HandsetSoft handsetSoft) {
this.handsetSoft = handsetSoft;
}
public abstract void run();
}
- 手機具體品牌類
/**
* HandsetM
*/
public class HandsetM extends AbstractHandset {
public HandsetM(HandsetSoft handsetSoft) {
super(handsetSoft);
}
@Override
public void run() {
this.handsetSoft.run();
}
}
/**
* HandsetN
*/
public class HandsetN extends AbstractHandset {
public HandsetN(HandsetSoft handsetSoft) {
super(handsetSoft);
}
@Override
public void run() {
this.handsetSoft.run();
}
}
- Main 類
/**
* Main
*/
public class Main {
public static void main(String[] args) {
HandsetM handsetM = new HandsetM(new HandsetGame());
handsetM.run();
HandsetN handsetN = new HandsetN(new HandsetMP3());
handsetN.run();
}
}
小結
橋接模式,實現了抽象和實現部分的分離,從而極大的提供了系統的靈活性,讓抽象部分和實現部分獨立開來,這有助於系統進行分層設計,從而產生更好的結構化系統。對於系統的高層部分,只需要知道抽象部分和實現部分的接口就可以了,其它的部分由具體業務來完成。橋接模式替代多層繼承方案,可以減少子類的個數,降低系統的管理和維護成本。
橋接模式要求正確識別出系統中兩個獨立變化的維度(抽象和實現),因此其使用範圍有一定的侷限性,即需要有這樣的應用場景。