引用
橋我們大家都熟悉,顧名思義就是用來將河的兩岸聯(lián)系起來的。而此處的橋是用來將兩個獨立的結(jié)構(gòu)聯(lián)系起來,而這兩個被聯(lián)系起來的結(jié)構(gòu)可以獨立的變化,所有其他的理解只要建立在這個層面上就會比較容易。
基本介紹
- 橋接模式(Bridge)是指將實現(xiàn)與抽象放在兩個不同的類層次中,是兩個層次可以獨立改變。
- 該模式基于類的最小設(shè)計原則(擴展功能時盡量少的增加類),通過使用封裝、聚合、繼承等行為讓不同的類承擔(dān)不同的職責(zé)。
- 主要特點是把抽象和行為實現(xiàn)分離開來,從而可以保持各部分的獨立性以及對他們的功能擴展。
- 橋梁模式的用意是將抽象化與實現(xiàn)化脫耦,使得二者可以獨立地變化。
原理類圖
?橋接(Bridge)模式包含以下主要角色:
-
client:橋接模式的調(diào)用者
- Implementor:實現(xiàn)化角色,它是接口或者抽象類,定義角色必需的行為和屬性;這個接口不一定要與Abstraction的接口完全一致,事實上這兩個接口可以完全不同,一般而言,Implementor接口僅提供基本操作,而Abstraction定義的接口可能會做更多更復(fù)雜的操作。Implementor接口對這些基本操作進行了聲明,而具體實現(xiàn)交給其子類。通過關(guān)聯(lián)關(guān)系,Abstraction不僅擁有自己的方法,還可以調(diào)用Implementor中定義的方法,使用關(guān)聯(lián)關(guān)系來替代繼承關(guān)系;
- ConcreteImplementor:具體實現(xiàn)化角色,實現(xiàn)接口或抽象類定義的方法或?qū)傩浴T诓煌腃oncreteImplementor中提供基本操作的不同實現(xiàn),在程序運行時,ConcreteImplementor對象將替換其父類對象,提供給抽象類具體的業(yè)務(wù)操作方法;
- Abstraction:抽象化角色,定義出該角色的行為,同時保存一個對實現(xiàn)化角色的引用;它一般是抽象類而不是接口,其中定義了一個Implementor(實現(xiàn)類接口)類型的對象并可以維護該對象,它與Implementor之間具有關(guān)聯(lián)關(guān)系,它既可以包含抽象業(yè)務(wù)方法,也可以包含具體業(yè)務(wù)方法;
- RefinedAbstraction:擴充抽象類角色,引用實現(xiàn)化角色對抽象化角色進行擴充。通常情況下,它不再是抽象類而是具體類,它實現(xiàn)了在Abstraction中聲明的抽象業(yè)務(wù)方法,在RefinedAbstraction中可以調(diào)用在Implementor中定義的業(yè)務(wù)方法;
從UML圖看,這里的抽象類和接口是聚合關(guān)系,就是調(diào)用和被調(diào)用的關(guān)系;RefinedAbstraction的父類聚合了接口,RefinedAbstraction調(diào)用接口的具體實現(xiàn)
優(yōu)缺點
通過上面的講解,我們能很好的感覺到橋接模式遵循了里氏替換原則和依賴倒置原則,最終實現(xiàn)了開閉原則,對修改關(guān)閉,對擴展開放。這里將橋接模式的優(yōu)缺點總結(jié)如下。??
優(yōu)點:
- 分離抽象接口及其實現(xiàn)部分。橋接模式使用“對象間的關(guān)聯(lián)關(guān)系”解耦了抽象和實現(xiàn)之間固有的綁定關(guān)系,使得抽象和實現(xiàn)可以沿著各自的維度來變化。所謂抽象和實現(xiàn)沿著各自維度的變化,也就是說抽象和實現(xiàn)不再在同一個繼承層次結(jié)構(gòu)中,而是“子類化”它們,使它們各自都具有自己的子類,以便任何組合子類,從而獲得多維度組合對象。
- 在很多情況下,橋接模式可以取代多層繼承方案,多層繼承方案違背了“單一職責(zé)原則”,復(fù)用性較差,且類的個數(shù)非常多,橋接模式是比多層繼承方案更好的解決方法,它極大減少了子類的個數(shù)。
- 橋接模式提高了系統(tǒng)的可擴展性,在兩個變化維度中任意擴展一個維度,都不需要修改原有系統(tǒng),符合“開閉原則”。
缺點:
- 橋接模式的使用會增加系統(tǒng)的理解與設(shè)計難度,由于關(guān)聯(lián)關(guān)系建立在抽象層,要求開發(fā)者一開始就針對抽象層進行設(shè)計與編程。
- 橋接模式要求正確識別出系統(tǒng)中兩個獨立變化的維度,因此其使用范圍具有一定的局限性,如何正確識別兩個獨立維度也需要一定的經(jīng)驗積累。
模式的實現(xiàn)
橋接模式的代碼如下:
package bridge;
public class BridgeTest {
public static void main(String[] args) {
Implementor imple = new ConcreteImplementorA();
Abstraction abs = new RefinedAbstraction(imple);
abs.Operation();
}
}
//實現(xiàn)化角色
interface Implementor {
public void OperationImpl();
}
//具體實現(xiàn)化角色
class ConcreteImplementorA implements Implementor {
public void OperationImpl() {
System.out.println("具體實現(xiàn)化(Concrete Implementor)角色被訪問");
}
}
//抽象化角色
abstract class Abstraction {
protected Implementor imple;
protected Abstraction(Implementor imple) {
this.imple = imple;
}
public abstract void Operation();
}
//擴展抽象化角色
class RefinedAbstraction extends Abstraction {
protected RefinedAbstraction(Implementor imple) {
super(imple);
}
public void Operation() {
System.out.println("擴展抽象化(Refined Abstraction)角色被訪問");
imple.OperationImpl();
}
}
?
程序的運行結(jié)果如下:
擴展抽象化(Refined Abstraction)角色被訪問
具體實現(xiàn)化(Concrete Implementor)角色被訪問
案例場景模擬
假設(shè)設(shè)計一個日志系統(tǒng),這個系統(tǒng)可以記錄多種日志類型,如交易日志,數(shù)據(jù)庫日志,用戶操作日志等,同時,這個系統(tǒng)還支持多種日志的表現(xiàn)形式。如xml文件,文本文件,數(shù)據(jù)庫庫數(shù)據(jù),E-mail等。
??? 抽象:日志的種類。
??? 實現(xiàn):日志的表現(xiàn)方式。
實現(xiàn)代碼如下:
Log源代碼
public abstract class Log{
protected LogSave logSave;
public Log(LogSave logSave){
this.logSave=logSave;
}
public abstract void writeToLog();
}
LogSave源代碼
public abstract class LogSave{
public abstract void write();
}
下面是三個Log的子類
TradLog源代碼
public class TradLog extends Log{
public TradLog(LogSave logSave){
super(logSave);
}
@Override
public void writeToLog(){
System.out.println("寫入TradLog數(shù)據(jù)");
this.logSave.write();
}
}
DbLog源代碼
public class DbLog extends Log{
public DbLog(LogSave logSave){
super(logSave);
}
@Override
public void writeToLog(){
System.out.println("寫入DbLog數(shù)據(jù)");
this.logSave.write();
}
}
UserLog源代碼
public class UserLog extends Log{
public UserLog(LogSave logSave){
super(logSave);
}
@Override
public void writeToLog(){
System.out.println("寫入UserLog數(shù)據(jù)");
this.logSave.write();
}
}
下面是LogSave的三個實現(xiàn)類
XmlImpl源代碼
public class XmlImpl extends LogSave{
@Override
public void write(){
System.out.println("使用xml方式存儲");
}
}
TextImpl源代碼
public class TextImpl extends LogSave{
@Override
public void write(){
System.out.println("使用文本方式存儲");
}
}
?EmailImpl源代碼
public class EmailImpl extends LogSave{
@Override
public void write(){
System.out.println("使用發(fā)郵件的方式存儲");
}
}
實現(xiàn)不能和抽象發(fā)生耦合,而只能由抽象和實現(xiàn)發(fā)生耦合。
下面是啟動類展示最終結(jié)果:
Client源代碼
public class Client{
public static void main(String[] args){
Log log=new UserLog(new XmlImpl());
log.writeToLog();
Log log2=new DbLog(new EmailImpl());
log2.writeToLog();
}
}
運行結(jié)果如下:
寫入UserLog數(shù)據(jù)
使用xml方式存儲
寫入DbLog數(shù)據(jù)
使用發(fā)郵件的方式存儲
應(yīng)用場景
- 如果一個系統(tǒng)需要在構(gòu)件的抽象化角色和具體化角色之間增加更多的靈活性,避免在兩個層次之間建立靜態(tài)的繼承聯(lián)系,通過橋接模式可以使它們在抽象層建立一個關(guān)聯(lián)關(guān)系。
- 對于那些不希望使用繼承或因為多層次繼承導(dǎo)致系統(tǒng)類的個數(shù)急劇增加的系統(tǒng),橋接模式尤為適用。
- 一個類存在兩個獨立變化的維度,且這兩個維度都需要進行擴展。
- 常用的場景:
- JDBC驅(qū)動程序
- 日志框架
- 銀行轉(zhuǎn)賬系統(tǒng)
- 轉(zhuǎn)賬分類:網(wǎng)上轉(zhuǎn)賬、柜臺轉(zhuǎn)賬、ATM轉(zhuǎn)賬
- 用戶類型:普通用戶、銀卡用戶、金卡用戶
- 消息管理
- 消息類型:即時消息、延時消息
- 消息分類:手機短信、郵件信息、QQ消息
橋接模式模式的擴展
在軟件開發(fā)中,有時橋接(Bridge)模式可與適配器模式聯(lián)合使用。當(dāng)橋接(Bridge)模式的實現(xiàn)化角色的接口與現(xiàn)有類的接口不一致時,可以在二者中間定義一個適配器將二者連接起來,其具體結(jié)構(gòu)圖如圖橋接模式與適配器模式聯(lián)用的結(jié)構(gòu)圖所示。文章來源:http://www.zghlxwxcb.cn/news/detail-657644.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-657644.html
小結(jié)
- 對于系統(tǒng)的高層來說,只需要知道抽象部分和實現(xiàn)部分的接口就夠了,其他部分由具體業(yè)務(wù)來完成
- 橋接模式代替多層繼承方案,可以減少子類的個數(shù),降低系統(tǒng)的管理和維護成本
- 橋接模式要求正確識別出系統(tǒng)中的兩個獨立變化維度,因此其使用范圍有一定的局限性,適用于一定的應(yīng)用場景
到了這里,關(guān)于設(shè)計模式——橋接模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!