橋接模式(Bridge)
橋接模式屬於結構型設計模式,其核心的設計思想就是將抽象化結構和實現化結構隔離開來,使兩者達到解耦的目的,同時又將兩者通過聚合連接起來,配合完成功能。目的就是將抽象部分與實現部分分離,使它們都可以獨立的變化,同時它們之間還存在聯繫,畢竟使用者最終還是要通過調用抽象化的對象去間接調用具體實現化的對象。橋接模式可以讓抽象化結構和實現化結構達到極其良好的擴展能力,這是該模式最大的優點所在。
橋接模式的角色
- 抽象化(Abstraction)
定義抽象化的操作方法,同時需要依賴實現化對象。
- 修正抽象化(RefinedAbstraction)
實現抽象化對象,可以修正和擴展抽象化定義的功能,同時通過父類抽象化已經依賴的實現化對象去調用其接口方法,最終達到調用具體實現對象的功能。
- 實現化(Implementor)
實現化其實就是一個普通的接口,定義真正實現化功能的接口,該接口只要符合可以供修正抽象化對象調用即可,其餘方面沒有任何的必需聯繫。可以理解抽象化是一個高層次的結構,是維度較大的功能,而實現化是一個低層次的結構,是維度較小的功能,所以很多時候抽象化的對象都會同時依賴多個實現化對象去共同完成功能。
- 具體實現化(ConcreateImplementor)
具體實現化對象繼承並實現實現化接口,其他方面無需關心,這是橋接模式優點的具體體現,具體實現化對象和抽象化對象是完全解耦的結構,所以具體實現化對象具有良好的擴展能力,代碼的修改和擴展不會影響到抽象化對象。對於調用者來說,調用抽象化對象功能時只需要傳遞不同的具體化對象,即可達到動態地轉換自己想要的功能的目的。
實踐橋接模式
假設現在我們需要實現一個消息通知的功能,通知的類型包括了短信和郵件,同時消息發送之前需要記錄下消息通知的日誌。我們來分析一波這個需求,消息通知功能可以理解爲是一個高層次結構的方法,因爲在發送通知前後還可能包含有做其他的操作,是一個聚集了多個細粒度小功能的接口,而短信和郵件則可以理解爲是一個低層次結構的方法,即細粒度的小功能接口, 所以我們可以使用橋接模式去實現該功能,最終可以達到不僅功能實現,而且還能夠隨時地修改、擴展短信和郵件的具體實現,例如需要切換短信的服務提供商,直接修改短信具體實現對象即可,不需要修改上層結構修正抽象化對象的代碼。
public abstract class NotifyApi {
/**依賴實現化接口對象*/
protected MessageApi messageApi;
public NotifyApi(MessageApi messageApi) {
this.messageApi = messageApi;
}
public abstract void notify(String toUser);
}
定義實現化接口,包含細粒度的接口功能,發送消息給某個用戶
public interface MessageApi {
/**發送消息給某個用戶*/
void send(String toUser);
}
定義修正抽象化對象,通過抽象化依賴的實現化接口對象去掉用接口方法,同時還可以擴展抽象化接口例如記錄通知日誌。
public class MessageNotify extends NotifyApi {
public MessageNotify(MessageApi messageApi) {
super(messageApi);
}
@Override
public void notify(String toUser) {
System.out.println("其他操作,記錄日誌");
messageApi.send(toUser);
}
}
擁有良好擴展能力的具體實現化對象。
public class EmailMessage implements MessageApi {
@Override
public void send(String toUser) {
System.out.println("發送郵件給"+toUser);
}
}
public class SMSMessage implements MessageApi {
@Override
public void send(String toUser) {
System.out.println("發送短信給"+toUser);
}
}
客戶端調用通過切換不同的具體實現對象,動態切換功能。
public class Main {
public static void main(String[] args) {
//發送郵件給小明
NotifyApi notifyApi = new MessageNotify(new EmailMessage());
notifyApi.notify("小明");
//發送短信給小張
notifyApi = new MessageNotify(new SMSMessage());
notifyApi.notify("小張");
}
}
其他操作,記錄日誌
發送郵件給小明
其他操作,記錄日誌
發送短信給小張
擴展設計模式-類層次結構
有的資料中講到橋接模式的作用就是在“類的功能層次結構”和“類的實現層次結構”之間搭建橋樑。我們來理解一下類層次結構,假設有一個類ObjA,如果我們想擴展它的功能,可以通過定義一個繼承了ObjA的子類ObjB,在ObjB添加新的功能方法即可,這樣的類層次結構就被稱爲“類的功能層次機構”。假設定義了一個接口InterA,然後通過子類去負責實現InterA的抽象方法,子類不是爲了擴展功能,而是去實現父類接口方法,這樣的類層次結構就被稱爲“類的實現層次結構”。
對照我們上面的例子NotifyApi和MessageNotify就是類的功能層次機構關係,MessageApi和 EmailMessage、SMSMessage就是類的實現層次結構關係。
在Java中的實際使用
橋接模式在java應用中一個典型的應用例子就是數據源。JdbcAccessor和JdbcTemplate分別扮演抽象化角色和修正抽象化角色,抽象化對象JdbcAccessor依賴實現化接口DataSource,DataSource提供了getConnection()接口方法,具體實現化對象有很多種,需要繼承DataSource去實現getConnection()方法。調用者通過JdbcTemplate操作數據庫的時候可以動態地切換不同的DataSource具體實現化對象,而上層結構和代碼不需要做任何的改動,這也體現了橋接設計模式的三個優點:
- 能夠讓抽象化結構和實現化結構達到分離解耦的目的。
- 爲具體實現化對象提供了良好的擴展能力。
- 客戶通過調用抽象化對象即可實現功能,隱藏功能的具體實現。