Java設計模式——橋模式
概述
橋模式(Bridge)是為瞭解決將抽象部分與實現部分分離,好讓他們都在自己的維度上有多維度地變化。這句話是好理解的,只是我在學習完橋模式之後,存在一些疑問,還好現在想通了。現在我就橋模式的設計思想和我的疑問一併發出,希望於你有益。
情境
現假設市面上有多種不同型號的電視機,和一些不同的遙控器生產產商。遙控器生產產商要為這些電視機進行生產遙控器,可是這些電視機型號太多,有一些電視機的型號太雜,甚至在後期會出現一些不同型號的電視機。
普通彙總方案
在這個一般方案中,遙控器產商要為每一種電視機生產一種遙控器。類圖如下
每個具體的遙控器都去繼承或是實現遙控器的抽象或是介面,並且在每個具體的遙控器內部都彙總了各自的電視機介面。這種方案可以解決問題,可以解決遙控器與電視機的對應關係。可是,卻有一個問題,就像上面情境中所說的,如果這裡的有一些新的電視機出現,那麼生產遙控器的產商還得去生產新的遙控器。這樣一來各自的遙控器數量不但不好把握,而且這樣的設計很繁雜。
橋模式
上面一般的彙總方案無法解決遙控器的一般性,對於新的機型無法相容和適應。對於這樣在抽象或是實現上會有多維度擴充的情況,我們就必須重新設計代碼結構了。下面是橋模式,以及橋模式是如何解決這個問題的。
定義
將抽象部分(Abstraction)與實現部分(Implementor)分離,使它們可以獨立地變化。
分析
橋模式的應用情境是某一個抽象或是實現可能存在多維度變化。就像上面的遙控器執行個體,我們在遙控器這個抽象上,可能會有不同的生產產商;在電視機這個實現上可能會RCA、Sony等等。橋模式可以讓遙控器的抽象和電視機的實現在各自的方向上多維度變化,而不用關心其他的事情。
在上面我也分析了一般的彙總方案是不可靠的,它的確可以解決一些問題,可是卻是繁瑣的,也是不必要的。
這裡再說一個大家可能都比較熟悉的例子。比如我們現在編寫的Java程式,與運行平台之間的關係。我們可以有很多很多的Java程式,而運行平台也可以是Windows、Linux或是Mac。我們的Java程式需要在所有的平台上能夠執行,每一個平台也要保證能夠全部的Java程式。
類圖
這裡我們讓遙控器的抽象類別彙總電視機的介面。因為所以的電視都實現電視機這個介面,那麼遙控器的抽象類別也就彙總了所有的電視機實現。這樣不管你電視機的型號如何改變,遙控器都可以不做修改也能繼續工作。
註:當時我在這裡存在一個小疑問,為什麼我們的電視機介面不是彙總到遙控器的子類中,而是彙總到遙控器的抽象類別中呢?也就是說,這裡我有沒有必要有一個遙控器的抽象類別?
現在我假設這裡不存在這個RemoteControl的抽象類別,那麼ConcreteRemote將持有TV這個介面,可是這樣在遙控器這個維度上都不好擴充了。橋模式的牛X之處就在於它可以讓多維度抽象和實現都可以在多維度上進行任意擴充。
邏輯實現
基於上面的類圖,可編寫Java代碼。
TV.java
public interface TV { public void on(); public void off(); public void tuneChannel(int channel);}
RCA.java
public class RCA implements TV { @Override public void on() { System.out.println("RCA被開啟了"); } @Override public void off() { System.out.println("RCA被關閉了"); } @Override public void tuneChannel(int channel) { System.out.println("切換到第" + channel + "頻道了"); }}
Sony.java
public class Sony implements TV { @Override public void on() { System.out.println("Sony被開啟了"); } @Override public void off() { System.out.println("Sony被開啟了"); } @Override public void tuneChannel(int channel) { System.out.println("切換到第" + channel + "頻道了"); }}
RemoteControl.java
public abstract class RemoteControl { protected TV tv = null; public RemoteControl(TV _tv) { this.tv = _tv; } public abstract void on(); public abstract void off(); public void setChannel(int channel) { if (tv != null) { tv.tuneChannel(channel); } }}
ConcreteRemote.java
public class ConcreteRemote extends RemoteControl { private int currentStation = 0; private final int MAX_STATION = 25; public ConcreteRemote(TV _tv) { super(_tv); } @Override public void on() { tv.on(); } @Override public void off() { tv.off(); } public void setChannel(int channel) { currentStation = channel; super.setChannel(currentStation); } public void nextChannel() { currentStation = (MAX_STATION + currentStation + 1) % MAX_STATION; super.setChannel(currentStation); } public void previousChannel() { currentStation = (MAX_STATION + currentStation - 1) % MAX_STATION; super.setChannel(currentStation); }}
模式評價
| 優點 |
缺點 |
| 電視機的實現被解耦,它和遙控器之間不再永久綁定 |
相對比較複雜 |
| 遙控器和電視機可以獨立擴充,且不會影響對方 |
|
Ref《Head First設計模式》