一、基本介紹
將實現與抽象放在兩個不同的層次中,使兩個層次可以獨立改變。
橋接模式基於類的最小設計原則,通過使用封裝、聚合、繼承等行爲讓不同的類承擔不同的職責。
它的主要特點是把抽象與行爲實現分離開,從而可以保持各部分的獨立性以及功能擴展。
二、橋接模式的結構
其中,Abstraction爲抽象化角色,定義出該角色的行爲,同時保存一個對實現化角色的引用;Implementor是實現化角色,它是接口或者抽象類,定義角色必需的行爲和屬性;RefinedAbstraction爲修正抽象化角色,引用實現化角色對抽象化角色進行修正;ConcreteImplementor爲具體實現化角色,實現接口或抽象類定義的方法或屬性。
三、橋接模式的優缺點
1、優點
(1)實現了抽象和實現部分的分離
橋接模式分離了抽象部分和實現部分,從而極大的提供了系統的靈活性,讓抽象部分和實現部分獨立開來,分別定義接口,這有助於系統進行分層設計,從而產生更好的結構化系統。對於系統的高層部分,只需要知道抽象部分和實現部分的接口就可以了。
(2)更好的可擴展性
由於橋接模式把抽象部分和實現部分分離了,從而分別定義接口,這就使得抽象部分和實現部分可以分別獨立擴展,而不會相互影響,大大的提供了系統的可擴展性。
(3)可動態的切換實現
由於橋接模式實現了抽象和實現的分離,所以在實現橋接模式時,就可以實現動態的選擇和使用具體的實現。
(4)實現細節對客戶端透明,可以對用戶隱藏實現細節。
2、缺點
(1)橋接模式的引入增加了系統的理解和設計難度,由於聚合關聯關係建立在抽象層,要求開發者針對抽象進行設計和編程。
(2)橋接模式要求正確識別出系統中兩個獨立變化的維度,因此其使用範圍有一定的侷限性。
四、橋接模式的應用場景
1、不希望或不適用使用繼承的場景
2、接口或抽象類不穩定的場景
3、重用性要求較高的場景
應用實例:
(1)開關。我們可以看到的開關是抽象的,不用管裏面具體怎麼實現;
(2)手機品牌與手機軟件。兩者間有一條聚合線,一個手機品牌可以有多個手機軟件。
不要一涉及繼承就考慮該模式,儘可能把變化的因素封裝到最細、最小的邏輯單元中,避免風險擴散。
當發現類的繼承有n層時,可以考慮使用該模式。
五、代碼實現
1、品牌
package designMode.advance.bridge;
public interface Brand {
void open();
void close();
void call();
}
2、具體品牌
package designMode.advance.bridge;
public class Vivo implements Brand {
@Override
public void open() {
System.out.println(" Vivo手機開機 ");
}
@Override
public void close() {
System.out.println(" Vivo手機關機 ");
}
@Override
public void call() {
System.out.println(" Vivo手機打電話 ");
}
}
package designMode.advance.bridge;
public class XiaoMi implements Brand {
@Override
public void open() {
System.out.println(" 小米手機開機 ");
}
@Override
public void close() {
System.out.println(" 小米手機關機 ");
}
@Override
public void call() {
System.out.println(" 小米手機打電話 ");
}
}
3、手機樣式,行爲類
package designMode.advance.bridge;
public abstract class Phone {
//組合品牌
private Brand brand;
//構造器
public Phone(Brand brand) {
super();
this.brand = brand;
}
protected void open() {
this.brand.open();
}
protected void close() {
brand.close();
}
protected void call() {
brand.call();
}
}
package designMode.advance.bridge;
public class UpRightPhone extends Phone {
//構造器
public UpRightPhone(Brand brand) {
super(brand);
}
public void open() {
super.open();
System.out.println(" 直立樣式手機 ");
}
public void close() {
super.close();
System.out.println(" 直立樣式手機 ");
}
public void call() {
super.call();
System.out.println(" 直立樣式手機 ");
}
}
package designMode.advance.bridge;
public class FoldedPhone extends Phone {
//構造器
public FoldedPhone(Brand brand) {
super(brand);
}
public void open() {
super.open();
System.out.println(" 摺疊樣式手機 ");
}
public void close() {
super.close();
System.out.println(" 摺疊樣式手機 ");
}
public void call() {
super.call();
System.out.println(" 摺疊樣式手機 ");
}
}
4、測試類
package designMode.advance.bridge;
public class Client {
public static void main(String[] args) {
//獲取摺疊式手機 (樣式 + 品牌 )
Phone phone1 = new FoldedPhone(new XiaoMi());
phone1.open();
phone1.call();
phone1.close();
System.out.println("=======================");
Phone phone2 = new FoldedPhone(new Vivo());
phone2.open();
phone2.call();
phone2.close();
System.out.println("==============");
UpRightPhone phone3 = new UpRightPhone(new XiaoMi());
phone3.open();
phone3.call();
phone3.close();
System.out.println("==============");
UpRightPhone phone4 = new UpRightPhone(new Vivo());
phone4.open();
phone4.call();
phone4.close();
}
}
5、控制檯輸出
六、JDBC中的橋接模式
使用JCBC的時候,一直很困惑獲取connection的過程和原理,爲什麼把不同的數據庫驅動名稱放到Class.forName()中就能獲取到對應的數據庫連接呢?
Oracle爲例,通過Class.forName("oracle.jdbc.OracleDriver")類加載的時候執行靜態代碼塊將Driver註冊到DriverManager,DriverManager是個Driver容器,管理不同的Driver,這樣具體的數據Driver實現就統一交給容器管理,客戶端通過DriverManager執行驗證連接,獲取連接的操作。