1.1概述 將抽象部分與它的實現部分分離,使他們都可以獨立地變化。這就是橋接模式的定義。 抽象類或介面中可以定義若幹個抽象方法,習慣上將抽象方法稱作操作。抽象類或介面使程式的設計者忽略操作的細節,即不必考慮這些操作是如何實現的,當用戶程式面向抽象類或介面時,就不會依賴具體的實現,使系統具有很好的擴展 ...
1.1概述
將抽象部分與它的實現部分分離,使他們都可以獨立地變化。這就是橋接模式的定義。
抽象類或介面中可以定義若幹個抽象方法,習慣上將抽象方法稱作操作。抽象類或介面使程式的設計者忽略操作的細節,即不必考慮這些操作是如何實現的,當用戶程式面向抽象類或介面時,就不會依賴具體的實現,使系統具有很好的擴展性。但是,抽象類中的抽象方法總歸是需要子類去實現的,在大多數情況下抽象類的子類完全可以勝任這樣的工作,但是在某些情況下,子類可能會遇到一些難以處理的問題。
例如,電視臺系統中有一個抽象類CCTV,該類有一個抽象方法abstract void makeProgram()。現在為了滿足某些用戶看電視劇的需求,這裡給出了CCTV類的子類:CCTV8,該類的實例調用makeProgram()方法製作電視劇節目,因此子類CCTV8必須實現父類的makeProgram()方法,比如使用該方法製作出若幹幀影像。子類CCTV8的makeProgram()方法在製作出第一幀影像後,比如在第一幀影像顯示“CCTV8”,馬上就發現以下兩個問題:
(1)從第2幀開始應當是電視劇中的影像,而這樣的影像不應當由CCTV8類的makeProgram()方法負責製作。
(2)如果CCTV8在makeProgram()方法中強行給出了第2幀以後的各個影像,那麼用戶使用CCTV8類的實例看到的電視劇是一個固定的電視劇,如果有其他用戶想看新的電視劇,系統就必須新增新的CCTV子類,這對電視臺系統是一個非常不合理的一種設計,因為CCTV類應當只有一個負責製作“電視劇”節目的子類:CCTV8,而不是多個,也就是說,不能因為一個新的用戶要看不同的電視劇,就要出現一個專門為該用戶製作“電視劇”節目的子類。
針對上述問題,應當將實現和抽象放在兩個不同的類層次中,從而使他們可獨立的改變,即將一個抽象類中抽象方法的重要實現部分交給另外一個抽象類的子類或實現另外一個介面的類。比如,對於上述問題,應當將makeProgram()方法的實現交給另外一個抽象類:Program,該類定義了製作影像的makeTVfilm()方法。
我們應當重新設計抽象類CCTV類,使該類包含Program的引用,這就可以使CCTV類的子類CCTV8在實現makeProgram()方法時,將該方法的重要實現部分交給Program類的makeTVfilm()方法,即委托給Program子類的實例調用makeTVfilm()方法。
我們稱CCTV類和Program類之間的關係是橋接關係,也即是說,CCTV類的子類CCTV8僅僅在CCTV類和Program類之間起到一個“橋接”的作用,具體類關係如下圖一所示:
圖一:電視節目與電視劇製作的橋接關係
1.2模式的結構
橋接模式包括以下四種角色:
(1)抽象(Abstration):是一個抽象類,該抽象類含有Implementor聲明的變數,即維護一個Implementor類型對象。
(2)實現者(Implementor):實現者角色是一個介面(抽象類),該介面(抽象類)中的方法不一定與Abstration類中方法一致。Implementor介面(抽象類)負責定義基本操作,而Abstration類負責定義基於這些基本操作的較高層次的操作。
(3)細化抽象(Refined Abstration):細化抽象是抽象角色的一個子類,該子類在重寫(覆蓋)抽象角色中的抽象方法時,在給出一些必要的操作後,將委托所維護Implementor類型對象調用相應的方法。
(4)具體實現者(Concrete Implementor):具體實現者是實現(擴展)Implementor介面(抽象類)的類。
橋接模式結構的類圖如下圖二所示:
圖二:橋接模式的類圖
1.3橋接模式的優點
(1)橋接模式分離實現與抽象,使抽象和實現可以獨立的擴展。當修改實現的代碼時,不影響抽象的代碼,反之也一樣。
(2)滿足開-閉原則。抽象和實現者處在同層次,使系統可獨立地擴展者兩個層次。增加新的具體實現者,不需要修改細化對象,反之增加新的細化對象也不需要修改具體實現。
1.4適合使用橋接模式的情景
(1)不想讓抽象和某些重要的實現代碼是固定綁定關係,這部分實現可運行時動態決定。
(2)抽象和實現者都可以繼承的方法獨立地擴充而互不影響,程式在運行期間可能需要動態的將一個抽象的子類的實例與一個實現者的子類的實例進行組合。
(3)希望對實現者層次的代碼的修改對抽象層不產生影響,即抽象層的代碼不必重新編譯,反之亦然。