桥接模式coding
生活随笔
收集整理的這篇文章主要介紹了
桥接模式coding
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
現在我們來學習橋接模式,這個包建在結構這個包下面,bridge,那橋接模式就是把抽象和實現,分離出來,然后中間通過組合,來搭建他們之間的橋梁,那我們現在有一個場景,例如中國有很多銀行,有中國農業銀行,還有工商銀行,那這兩個銀行也比較好記,一個叫ABC Bank,還有叫ICBC Bank,我們就有自己的賬號,那關于我們的儲蓄賬號呢,分為定期賬號,還有活期賬號,定義賬號可以存三個月,半年一年,銀行也有一定的利息,而這種利息是比活期賬號利息高很多的,那我們現在抽象的來想一下,那這里面就分兩大塊,一塊是銀行,另外一塊就是我們的賬號,首先我們來創建一個類,這個類是一個接口,為什么要用接口呢,創建完這個接口之后,我們還要具體寫他的實現,這個接口就是Account賬號
一旦你看到這個圖,一定會很清晰的,這些都打開,那我們一起來看一下這個圖,我們一起來回顧一下,首先我們創建了Account,這個是什么呢,他是這個橋的實現接口,左側是實現層,右側是抽象層,所以橋接模式最重要的是把橋的左側和橋的右側,你要橋接的兩側,劃分清楚,Account可以理解成,他就是這個橋的實現接口,而下邊這兩個Account,一個是定期賬號,一個是活期賬號,他們兩個就是具體的實現類,他們來實現Account接口,然后注意,第三步我們創建了Bank,創建了一個抽象類Bank,用的是什么呢,使用了Account這個接口,這個就是橋接模式的核心,注意這個抽象類使用了Account接口,通過什么方式呢,通過組合的方式,所以這條線右側有一個菱形,一個Bank里面含有一個Account,那下邊的ICBCBank,還有ABCBank,他們就是具體繼承了Bank,這個抽象類具體的類實現,那我們通過這個橋接模式,把實現部分Account,和抽象部分Bank,進行一個橋接,那當然我們說的實現部分,是指Account的具體的接口實現類,而抽象部分,就是指Bank這個抽象類,而中間的這個橫線呢,也就是橋接模式的一個關鍵,連接兩個繼承體系的一個橋,當然我們這里面是組合,也有通過聚合方式實現橋接的,如果我們不用這種方式,會怎么樣呢,打個比方,我們首先寫一個Bank,然后這兩個銀行愛存不存,還有ABCBank,然后我們在ICBCBank下邊,再創建兩個賬號,一個是SavingAccount,另外一個是DepositAccount,同理呢ABCBank下邊,也會有這兩個賬號,那這導致了一個什么問題,如果我們銀行很多,還有賬號的類型很多的話,這個子類就要爆炸了,下邊會有無數個的類,那前面我們也有說,橋接模式在一定程度上,可以避免子類過多,子類劇增,子類爆炸的情況,那如果我們用剛剛我們說的方式,就是通過最簡單的一個繼承的方案,所以橋接模式通過組合的方式,通過復合復用原則,來達到抽象層,和實現層,他們兩之間進行分離,并且最重要的一點,他們兩可以獨立的發展,再創建一個銀行,在這里面創建銀行,繼承Bank就可以,在這里面創建一個賬號,繼承Account就可以,他們兩之間就可以無限組合,那這個就橋接模式的精華所在,希望你們能夠深入理解一下,在這個模式當中,使用組合優于繼承,這個效果是非常非常明顯的,那他到底有多方便呢,很簡單,我們來寫一下Test
注意中間是一個橋梁,最大的特色是連接兩個繼承體現中間的那座橋,也就是我們看到的一比一的關系,左邊是抽象部分,右邊是實現部分,抽象部分可以獨立的擴展自己,實現部分也可以獨立的擴展自己,可以加無數個銀行,而賬號這邊呢,可以加各種理財賬號,各種各樣的賬號,至少不管他們之間如何排列組合,我們都不會發生類爆炸的情況,剛才我們在前面也說了,如果用繼承的方式來實現的話,會是什么樣子,那希望通過我們的coding實戰,對橋接模式有更深刻的理解,還有千萬不要忘記委托行為的小坑
package com.learn.design.pattern.structural.bridge;/*** 在這里有兩個方法* * * @author Leon.Sun**/
public interface Account {/*** 一個呢是打開我們的賬號* 打開賬號又分為打開哪個銀行的賬號呢* 例如leon有工商銀行的賬號* 還有中國農業銀行的賬號* 所以這里也是一個抽象* 那既然打開賬號呢* 就要返回賬號* openAccount這么一個方法* * * @return*/Account openAccount();/*** 還有是查看我們賬戶的類型* 是活期儲蓄* 還是定期儲蓄* 還有一個showAccountType* 看一下這個賬號的類型* 就現在的場景而言* 我們有中國農業銀行* 中國工商銀行* 這是兩個銀行* 還有有活期賬號* 還有定期賬號* 這個呢是兩個不同類型的賬號* 他們交叉一下* 就會有四種組合* 那一旦說我們的銀行不斷的擴展* 賬號類型也不斷地擴展的話* 那么對于橋接模式* 就再適合不過了* 他們兩個都可以隨著自己的層級* 進行擴展* 隨著我們coding的時候呢* 希望對這一塊的理解呢* 會加深* 首先呢我們創建一個定期賬號* 來實現這個接口* DepositAccount* * */void showAccountType();}
package com.learn.design.pattern.structural.bridge;/*** 他來實現Account* 實現兩個方法* 這個賬號是一個定期賬號* 我們再創建一個活期賬號的類* 新建一個類* SavingAccount* DepositAccount是定期存款* 如果提前取出來的話需要交罰金的* * * * @author Leon.Sun**/
public class DepositAccount implements Account {/*** 寫一下這個類的實現* * */@Overridepublic Account openAccount() {/*** 首先輸出* "打開定期賬號"* * */System.out.println("打開定期賬號");/*** 返回值直接new一個* 非常適合回來來看* 寫完之后你們先體會* 回頭來給大家講* 因為我幾年前在學模式的時候* 當時從上至下的來學習的時候* 理解的并不是很透徹* 但是一旦寫完之后* 再回頭來看* 一切都非常清晰明了* 我們邊寫也會邊講* 一起來體會* 我們再回頭重點來講* 那我們繼續來coding* 那現在就得寫我們的銀行類* 創建一個類Bank* * */return new DepositAccount();}@Overridepublic void showAccountType() {/*** 這個是一個定期賬號* * 直接到這里* 這是一個定期賬號* 那這個時候F8通過* * */System.out.println("這是一個定期賬號");}
}
package com.learn.design.pattern.structural.bridge;/*** 他也實現Account接口* 實現這兩個方法* SavingAccount是隨時可以取錢的那種* * * @author Leon.Sun**/
public class SavingAccount implements Account {/*** 打開這個賬號需要返回這個賬號* * */@Overridepublic Account openAccount() {/*** 所以我們輸出一下打個標記* * */System.out.println("打開活期賬號");//.../*** new一個SavingAccount* * */return new SavingAccount();}@Overridepublic void showAccountType() {/*** 直接輸出"這是一個活期賬號"* * */System.out.println("這是一個活期賬號");}
}
package com.learn.design.pattern.structural.bridge;/*** 這個銀行類很簡單* 他要寫成一個抽象類* 為什么呢* 因為現在我們要把Account* 引入到Bank里邊* 然后通過這種組合的方式* 交給子類來實現他的行為* 而這個行為就是openAccount* 至少我要確定* 打開的是哪個銀行的賬號* 那首先呢既然要交給子類* * * @author Leon.Sun**/
public abstract class Bank {/*** protected* 聲明一個account* 子類能夠拿到Account* 然后我來寫一下他的構造器* * */protected Account account;/*** 構造器我可以把account拿過來* 也可以通過set注入的方式* * 然后在父類上也打一個斷點* * 所以就把這個account賦值給抽象類Bank* 里面組合的Account* F6單步* 可以看到這個時候已經有值了* * * @param account*/public Bank(Account account){/*** 然后賦值* 把這些斷點去掉* 看一下結果* 那在使用橋接模式的時候* 有一個小坑* 這個小坑是什么呢* 例如我們現在打開中國工商銀行賬號* 然后直接顯示了這是一個定期賬號* 這個沒有什么問題* 但是我們要注意* 我們委托之后* 到底有沒有使用他呢* 我們看一下* * */this.account = account;}/*** 然后我們要寫一個抽象方法* 那這個方法是什么呢* 正式Account接口的方法* 那一會就知道* 為什么我這個想抽象類里邊* 還要寫一個抽象方法* 而這個抽象方法* 和接口里面聲明的* 抽象方法是一樣的* 那這里面我也要強調一下* 聲明成一樣的方法名* 這個并不是強制的* 那我們聲明成一樣的方法名呢* 是為了你們更方便的理解* 因為Bank里面的具體的方法* 要委托給Account的openAccount* 這個方法* 所以就把它們聲明成一樣的方法名* 其實不叫一樣的方法名也是OK的* 只不過這種委托關系* 在我們這個case里邊* 邏輯比較簡單* 并不會增強這個openAccount方法* 所以就直接委托給他* 他們兩個的方法名是一樣的* 里邊的實現所表達的含義也是一樣的* 然后這里邊再說一下* 看到的Account類* 那在我們現在這個結構中* Account就是具體的實現* 因為我們要通過Account的接口實現* Bank就是抽象* 然后抽象類里面的某個行為* 委托給Account這個接口* 那前面我們也有說* 橋接模式是指抽象和實現分離* 那實現是什么呢* 實現正式Account的兩個實現類* 那Account是有名詞的含義* 那還有動詞* 動詞就是報賬 查賬* 我們可以認為Account是一個行為接口* 里面是兩個動作* 一個是open* 一個是show* 打開賬號* 還是查看賬號類型呢* 這些都是動作* 那這里面還要再強調一次* 抽象和實現分離* 在橋接模式當中* 抽象是指抽象類* 因為還有各種擴展* 而具體的實現呢* 一般也都是行為* 這里也說了* 當然不排除特殊情況* 這里面的account也是動詞* 那橋接模式當中的實現* 就是Account的兩個接口實現* 而這個方法名字* 并不強制一模一樣* 不過我們這里是強制委托* 如果方法要達到的目的是一模一樣的* 所以就直接copy這個方法名了* 這里面還是比較靈活的* 并沒有強制限制* 那我們現在來創建中國農業銀行* ABCBank* * * @return*/abstract Account openAccount();
}
package com.learn.design.pattern.structural.bridge;/*** 他繼承Bank* 這個抽象父類* * * @author Leon.Sun**/
public class ABCBank extends Bank {/*** 紅線說沒有構造器* 我們構造一個* 調用super* 調用父類的構造器* * * @param account*/public ABCBank(Account account) {super(account);}/*** 這里面實現就很簡單了* 構造的時候傳入的什么Account* 就返回什么Account* 而這個Account正式父類的Account* 所以這里面直接返回Account就可以了* * */@OverrideAccount openAccount() {/*** 直接輸出* "打開中國農業銀行賬號"* 同時我們建立一個愛存不存賬號* ICBCBank* * */System.out.println("打開中國農業銀行賬號");/*** 然后調用了ICBCBank* 很明顯這個就是ICBC的銀行* 所以他肯定知道這個是中國工商銀行* 那具體是什么賬號* 他把它再進行一個返回* 那這個返回之后* 就來到了DepositAccount* * 在這里我們有時候寫業務邏輯的時候* 經常有忘記委托的這種情況* 隱瞞了一個點* 這個平時在使用橋接模式的時候* 一定不要忘記* 不要把具體的實現自己完成* 而是要委托給Account來實現* 否則創建相同名字的方法* 也就沒有意義了* 因為只有通過具體的委托* 以后account里邊的openAccount方法* 如果擴展的話* Bank這里邊是不需要動的* 不要把這個實現移到openAccount里邊* 這里一定要注意* 一定要把你具體的行為委托出去* 委托給誰呢* 正是委托給注入的Account* 那我們再run一下* 來看一下實際的結果* 剛剛那個小坑也是故意埋下的一個伏筆* 希望通過這坑* 一定要印象深刻* 我們再看一下結果* * */account.openAccount();return account;}
}
package com.learn.design.pattern.structural.bridge;/*** 繼承Bank這個類* * @author Leon.Sun**/
public class ICBCBank extends Bank {/*** 然后構造器加上* * * @param account*/public ICBCBank(Account account) {/*** 進入這里* * F6* 現在來創建工商銀行* 并且把這個賬號拿過來了* 他呢又調用父類的構造器* * */super(account);}@OverrideAccount openAccount() {/*** 打開的是工商銀行賬號* 現在我們來看一下UML圖* * 注意這里* 我們打開中國工商銀行賬號之后* 我們要把具體的行為委托給Account* * */System.out.println("打開中國工商銀行賬號");/*** 調用它的openAccount* 這樣才是真正實現openAccount這個行為* 委托給account* 委托來執行* 所以ABCBank也是一樣的* * */account.openAccount();/*** 直接return account* */return account;}
}
package com.learn.design.pattern.structural.bridge;/*** * @author Leon.Sun**/
public class Test {public static void main(String[] args) {/*** 我們創建一個銀行* 愛存不存銀行* ICBCBank* 這里面放一個DepositAccount* * 首先我們進入他的構造器來看一下* * */Bank icbcBank = new ICBCBank(new DepositAccount());/*** 然后從這里面拿一個賬號* icbcBank.openAccount* 打開這個賬號* * 這里打開了中國工商銀行賬號* * 同時打開這個銀行之后* 我又打開了定期賬號* 這是因為我們把定期賬號* 注入到ICBC賬號里邊* 所以他打開賬號的時候* 首先打開中國工商銀行賬號* 然后打開里面具體的的定期賬號* * */Account icbcAccount = icbcBank.openAccount();/*** 然后調用它的showAccountType方法* * 這里是一個定期賬號* * 最后show一下AccountType* 也就是這個* 現在這個使用才是非常標準的使用方式* 現在我們再結合前面的原則來說* 如果我們不把具體的實現委托給Account* 這個接口的話* 那我們對ABC Account的實現* 是非常可能不符合迪米特原則的* 那我們回來再看一下* */icbcAccount.showAccountType();/*** 后面直接加一個2* 那現在我們來run一下* 我們來看一下結果* ***/Bank icbcBank2 = new ICBCBank(new SavingAccount());/*** 這里打開一個中國工商銀行賬號* * */Account icbcAccount2 = icbcBank2.openAccount();/*** 這個是一個活期賬號* * */icbcAccount2.showAccountType();/*** 這個時候我再創建一個ABCBank* 這里面就換一下了* SavingAccount* 這個時候即使我需要一個工商銀行的SavingAccount* 也是很容易的* 我們直接copy一份出來* * * */Bank abcBank = new ABCBank(new SavingAccount());/*** 打開中國農業銀行賬號* * */Account abcAccount = abcBank.openAccount();/*** 這是一個活期賬號* 那現在debug來跟一個* 非常簡單* 我們直接run debug* * */abcAccount.showAccountType();}
}
?
總結
以上是生活随笔為你收集整理的桥接模式coding的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 桥接模式讲解
- 下一篇: 桥接模式源码解析(jdk)