JAVA設計模式之橋接模式
概念:
在軟件系統中,某些類型由於自身的邏輯,它具有兩個或多個維度的變化,那麼如何應對這種“多維度的變化”?如何利用面嚮對象的技術來使得該類型能夠輕鬆的沿着多個方向進行變化,而又不引入額外的複雜度?這就要使用Bridge模式。
意圖:
將抽象部分與實現部分分離,使它們都可以獨立的變化。
——《設計模式》GOF
橋接模式(bridge),處理多層繼承結構,處理多維度變化的場景,將各個維度設計成獨立的繼承結構,使各個維度可以獨立的擴展在抽象層建立關聯。
由於一個對象有多個維度決定,導致多繼承方式,而java不支持多繼承,則需要使用多層繼承,導致類關係複雜且龐大,新增維度變化會導致類的膨脹,而且違反單一職責原則,一個類,會有兩個引起這個類變化的原因。
類圖
應用:
JDBC驅動程序
AWT中的Peer架構
銀行日誌管理:
格式分類:操作日誌,交易日誌,異常日誌
距離分類:本地記錄日誌,異地記錄日誌
人力資源系統中的獎金計算模塊:
獎金分類:個人獎金,團體獎金,激勵獎金
部門分類:人事部門,銷售部門,研發部門
OA系統中的消息處理:
業務類型:普通消息,加急消息,特級消息
發送消息方式:系統內消息,手機短信,郵件
代碼:
採用橋接模式之前:
//基類 路
class Road {
void run() {
System.out.println("路");
}
}
//市區街道
class Street extends Road {
void run() {
System.out.println("市區街道");
}
}
//高速公路
class SpeedWay extends Road {
void run() {
System.out.println("高速公路");
}
}
//小汽車在市區街道行駛
class CarOnStreet extends Street {
void run() {
System.out.println("小汽車在市區街道行駛");
}
}
//小汽車在高速公路行駛
class CarOnSpeedWay extends SpeedWay {
void run() {
System.out.println("小汽車在高速公路行駛");
}
}
//公交車在市區街道行駛
class BusOnStreet extends Street {
void run() {
System.out.println("公交車在市區街道行駛");
}
}
//公交車在高速公路行駛
class BusOnSpeedWay extends SpeedWay {
void run() {
System.out.println("公交車在高速公路行駛");
}
}
//測試
public static void main(String[] args) {
//小汽車在高速公路行駛
CarOnSpeedWay carOnSpeedWay = new CarOnSpeedWay();
carOnSpeedWay.run();
//公交車在市區街道行駛
BusOnStreet busOnStreet = new BusOnStreet();
busOnStreet.run();
}
採用橋接模式後:
abstract class AbstractRoad{
AbstractCar aCar;
void run(){};
}
abstract class AbstractCar{
void run(){};
}
class Street extends AbstractRoad{
@Override
void run() {
// TODO Auto-generated method stub
super.run();
aCar.run();
System.out.println("在市區街道行駛");
}
}
class SpeedWay extends AbstractRoad{
@Override
void run() {
// TODO Auto-generated method stub
super.run();
aCar.run();
System.out.println("在高速公路行駛");
}
}
class Car extends AbstractCar{
@Override
void run() {
// TODO Auto-generated method stub
super.run();
System.out.print("小汽車");
}
}
class Bus extends AbstractCar{
@Override
void run() {
// TODO Auto-generated method stub
super.run();
System.out.print("公交車");
}
}
public static void main(String[] args){
AbstractRoad speedWay = new SpeedWay();
speedWay.aCar = new Car();
speedWay.run();
AbstractRoad street = new Street();
street.aCar = new Bus();
street.run();
}
通過對象組合的方式,Bridge 模式把兩個角色之間的繼承關係改爲了耦合的關係,從而使這兩者可以從容自若的各自獨立的變化,這也是Bridge模式的本意。
這樣增加了客戶程序與路與汽車的耦合。其實這樣的擔心是沒有必要的,因爲這種耦合性是由於對象的創建所帶來的,完全可以用創建型模式去解決。在應用時結合創建型設計模式來處理具體的問題
總結
- Bridge模式使用“對象間的組合關係”解耦了抽象和實現之間固有的綁定關係,使得抽象和實現可以沿着各自的維度來變化。
- 所謂抽象和實現沿着各自維度的變化,即“子類化”它們,得到各個子類之後,便可以任意它們,從而獲得不同路上的不同汽車。
- Bridge模式有時候類似於多繼承方案,但是多繼承方案往往違背了類的單一職責原則(即一個類只有一個變化的原因),複用性比較差。Bridge模式是比多繼承方案更好的解決方法。
- Bridge模式的應用一般在“兩個非常強的變化維度”,有時候即使有兩個變化的維度,但是某個方向的變化維度並不劇烈——換言之兩個變化不會導致縱橫交錯的結果,並不一定要使用Bridge模式。
橋接模式可以取代多層繼承的方案。多層繼承違背了單一職責原則,複用性差,類的個數非常多。橋接模式可以極大的減少子類的個數,從而降低管理和維護成本。
橋接模式極大的提高了系統的可擴展性,在兩個變化維度中任意擴展一個維度,都不需要修改原有的系統,符合開閉原則。