模式定義
官方定義:橋接模式就是將抽象部分與現實部分進行分離,使它們可以獨立變化。橋接模式將繼承關係轉化為關聯關係,它降低了類與類之間的耦合度,減少了系統中類的數量,也減少了程式碼量。
優缺點
-
優點
-
-
提高了系統的可擴充性。在兩個維度中改變其中任何一個都不會影響到另一個維度,也不需要修改原有的系統。
-
-
缺點
-
該模式的引入會增加系統的理解與設計難度,由於聚合關聯關係在抽象層,所以要求開發者針對抽象進行設計與程式設計。
-
橋接模式要求必須正確的識別出兩個維度的變化,因此其使用範圍有一定的限制性。
-
模式使用場景
-
系統需要在抽象層和實現層增加更多的靈活性,避免兩個層次之間建立靜態的繼承關係。
-
對於不希望通過繼承導致類的數量過多的系統,橋接模式尤為適用。
-
一個類存在兩個獨立的維度,並且這兩個維度都需要擴充。
上面的官方沒有聽懂很正常,下面會針對每一個名詞每種情況進行分析,並且配合類圖和程式碼例子給讀者最清晰的思路。
舉個例子
就拿各個廠商品牌的手機來說,現在有 華為、小米、IPhone 三個品牌,這個時候我們需要生產這三個品牌的手機,需要怎麼做呢?
這是符合上述中生產多個品牌手機的理想架構,很簡單明瞭,首先定義一個Phone的抽象類,然後由各個品牌去進行具體的實現,我們只需要在客戶端中進行呼叫就可以了。可是現在有個新的需求,我們生產的手機款式並不是單一的,每個品牌的手機有多種顏色,如果這個時候需要你來設計一個類圖會怎樣設計呢?根據上圖中的架構可能會設計成這樣。
我們可以看出每個品牌手機都有自己多種顏色的具體實現,這樣設計的缺點就很明顯的顯露出來了,結合我們文章開頭所描述的缺點可以一一對應上。上面設計中使用了靜態繼承 顏色和手機的具體實現中存在了靜態繼承不具備靈活性並且難以擴充,如果說後面又增加了新的顏色,那麼就需要在每個品牌的手機顏色中都新增一個新的顏色實現類。 如果新增了一個品牌的手機,必須新增了OPPO手機,那麼就會在需要多個類去繼承OPPO品牌手機的類來實現多種顏色的手機制造。
所以在上面的總結匯總我們發現了此時的架構就存在兩個維度即顏色和品牌,在這連個維度中擴充任何一方都會影響到另一個維度,擴充性差,而且會增加系統中類的數量增加程式碼量。
所以這個時候引進橋接設計模式就很有必要,下面我們再來看看文章開頭所涉及到的加粗部分。
-
將抽象部分與現實部分進行分離
也就說將顏色和手機之間的繼承關係取消,改為關聯關係。
-
獨立變化
如果將顏色和手機之間的靜態繼承關係改為關聯關係,那麼這兩個維度就可以進行所以的增加、刪除、修改,不會影響到另外一方,因為顏色這個維度是作為一個成員物件被引進到了手機類中了,沒有存在繼承關係。
-
橋接模式將繼承關係轉化為關聯關係、降低了類與類之間的耦合度
不存在繼承關係沒有父子關係,兩個維度平級,可以進行任意修改。
-
系統中類的數量
將繼承改為關聯,也就是將兩個維度組合起來,不需要一個維度下面跟隨另一個維度的多種實現。
如果這個時候我們再來理解文章開頭所說的優缺點應該就可以很輕鬆的理解了。說了這麼多我們接下來看一下關於這個例子使用橋接模式的類圖
這個時候我們可以看到 Color不在繼承與Phone,而且通過關聯的方式將兩個維度關聯起來,這樣無論哪個維度有變化了都不會影響到另外一個維度。下面看程式碼
package cn.hsh.study.abstraction;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:46
*/
public abstract class Phone {
protected PhoneColor phoneColor;
public void setPhoneColor(PhoneColor phoneColor) {
this.phoneColor = phoneColor;
}
/**
* 打電話
*/
public abstract void call();
}
package cn.hsh.study.abstraction.impl;
import cn.hsh.study.abstraction.Phone;
/**
* @author shaohua
* @date 2021/4/8 20:47
*/
public class HuaWei extends Phone {
public void call() {
System.out.println(super.phoneColor.getColor() + "華為手機打電話");
}
}
package cn.hsh.study.abstraction.impl;
import cn.hsh.study.abstraction.Phone;
/**
* @author shaohua
* @date 2021/4/8 20:47
*/
public class Mi extends Phone {
public void call() {
System.out.println(super.phoneColor.getColor() + "小米手機打電話");
}
}
package cn.hsh.study.abstraction.impl;
import cn.hsh.study.abstraction.Phone;
/**
* @author shaohua
* @date 2021/4/8 20:47
*/
public class Oppo extends Phone {
public void call() {
System.out.println(super.phoneColor.getColor() + "oppo手機打電話");
}
}
package cn.hsh.study.color;
/**
* @author shaohua
* @date 2021/4/8 20:49
*/
public interface PhoneColor {
/**
* 獲取顏色
* @return 顏色資訊
*/
String getColor();
}
package cn.hsh.study.color.impl;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:51
*/
public class Black implements PhoneColor {
public String getColor() {
return "黑色";
}
}
package cn.hsh.study.color.impl;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:50
*/
public class Blue implements PhoneColor {
public String getColor() {
return "藍色";
}
}
package cn.hsh.study.color.impl;
import cn.hsh.study.color.PhoneColor;
/**
* @author shaohua
* @date 2021/4/8 20:51
*/
public class Red implements PhoneColor {
public String getColor() {
return "紅色";
}
}
package cn.hsh.study;
import cn.hsh.study.abstraction.impl.Mi;
import cn.hsh.study.color.PhoneColor;
import cn.hsh.study.color.impl.Blue;
/**
* @author shaohua
* @date 2021/4/8 19:59
*/
public class Client {
public static void main(String[] args) {
//紅色的小米手機
Mi mi = new Mi();
PhoneColor miColor = new Blue();
mi.setPhoneColor(miColor);
mi.call();
}
}
下面是輸出結果
可以看出來無論兩個維度怎麼變化,我們都可以在兩個維度中分別構造出對應的物件,然後將其組合起來,橋接模式中所謂的橋無非就是一個維度中抽象層中所關聯的另外一個維度的引用,比如Phone抽象類中的Color成員。
模式總結
橋接模式實現了抽象化與實現化的脫耦,讓他們互相獨立,不會影響到對方,對於獨立變化的維度,所用橋接模式在合適不過了。