摘要:適配器模式橋接模式過(guò)濾器模式組合模式裝飾器模式外觀模式享元模式代理模式行為型模式這些設(shè)計(jì)模式特別關(guān)注對(duì)象之間的通信。對(duì)象適配器另外一種適配器模式是對(duì)象適配器,它不是使用多繼承或繼承再實(shí)現(xiàn)的方式,而是使用直接關(guān)聯(lián),或者稱為委托的方式。
設(shè)計(jì)模式匯總 創(chuàng)建型模式
這些設(shè)計(jì)模式提供了一種在創(chuàng)建對(duì)象的同時(shí)隱藏創(chuàng)建邏輯的方式,而不是使用新的運(yùn)算符直接實(shí)例化對(duì)象。這使得程序在判斷針對(duì)某個(gè)給定實(shí)例需要?jiǎng)?chuàng)建哪些對(duì)象時(shí)更加靈活。
工廠模式(Factory Pattern)
抽象工廠模式(Abstract Factory Pattern)
單例模式(Singleton Pattern)
建造者模式(Builder Pattern)
原型模式(Prototype Pattern)
結(jié)構(gòu)型模式這些設(shè)計(jì)模式關(guān)注類(lèi)和對(duì)象的組合。繼承的概念被用來(lái)組合接口和定義組合對(duì)象獲得新功能的方式。
適配器模式(Adapter Pattern)
橋接模式(Bridge Pattern)
過(guò)濾器模式(Filter、Criteria Pattern)
組合模式(Composite Pattern)
裝飾器模式(Decorator Pattern)
外觀模式(Facade Pattern)
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
行為型模式這些設(shè)計(jì)模式特別關(guān)注對(duì)象之間的通信。
責(zé)任鏈模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解釋器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
備忘錄模式(Memento Pattern)
觀察者模式(Observer Pattern)
狀態(tài)模式(State Pattern)
空對(duì)象模式(Null Object Pattern)
策略模式(Strategy Pattern)
模板模式(Template Pattern)
訪問(wèn)者模式(Visitor Pattern)
1 適配器模式 定義將一個(gè)類(lèi)的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類(lèi)可以在一起工作。
我們用圖來(lái)形象的解釋這一概念:
這里的重點(diǎn)在于,老接口有特殊功能,我們不忍舍棄,比如只有歐洲的插頭(老接口)能從插座里獲得電,沒(méi)有電我們過(guò)不下去。這個(gè)功能我們無(wú)法舍棄
為了繼續(xù)享受這個(gè)特殊功能,我們使用適配器模式,讓我們手中的美國(guó)的插頭(新接口),擁有老接口的能力。
例如一個(gè)美國(guó)人說(shuō)英語(yǔ),一個(gè)中國(guó)人說(shuō)中文,為了跟美國(guó)人做生意,說(shuō)英文這個(gè)功能我們無(wú)法舍棄,但是我們是中國(guó)人,天生不會(huì)說(shuō)英文。于是兩者想要交流,就需要一個(gè)適配器,來(lái)充當(dāng)溝通兩者的工作?,F(xiàn)在,我們希望讓一個(gè)能說(shuō)中國(guó)話的個(gè)體(實(shí)現(xiàn)說(shuō)中文的接口的類(lèi)),開(kāi)口說(shuō)英文。
角色目標(biāo)接口(Target)(中文溝通能力的接口):定義了我們希望用來(lái)承載被適配類(lèi)特殊功能的方法的接口,比如例子中,我們希望用中國(guó)人的說(shuō)話方法,承載美國(guó)人的speak功能,說(shuō)話方法就定義在該接口中。
目標(biāo)類(lèi)(Target class)(中國(guó)人類(lèi)):我們所期待的擁有特殊功能的具體類(lèi),也就是要說(shuō)英文的類(lèi)。
需要適配的類(lèi)(Adaptee)(美國(guó)人類(lèi)):需要適配的類(lèi)或適配者類(lèi),類(lèi)中還有我們還不忍舍棄的功能,我們需要迂回實(shí)現(xiàn)他
適配器(Adapter)(翻譯類(lèi)):通過(guò)包裝一個(gè)需要適配的對(duì)象,把原接口轉(zhuǎn)換成目標(biāo)接口。
類(lèi)適配器適配器有兩種主要的實(shí)現(xiàn),我們先看第一種——類(lèi)適配器
具體實(shí)現(xiàn)// 被適配類(lèi),已存在的、具有還有用處的特殊功能、但不符合我們既有的標(biāo)準(zhǔn)接口的類(lèi) //——本例中即為一個(gè)會(huì)說(shuō)f**k的美國(guó)人(你可以看作這個(gè)美國(guó)人實(shí)現(xiàn)了說(shuō)英文的接口,不過(guò)這個(gè)無(wú)關(guān)緊要,省略),他說(shuō)的話我們聽(tīng)不懂 class American{ public void speak() { System.out.println("f**k"); } }
// 目標(biāo)接口,或稱為標(biāo)準(zhǔn)接口 ——這里是一個(gè)說(shuō)中文能力的接口,他定義了方法“說(shuō)話”。 interface SpeakChinese { public void shuoHua(); }
// 具體目標(biāo)類(lèi),只提供普通功能 ——這里我們的具體實(shí)現(xiàn)是一個(gè)中國(guó)人類(lèi),他實(shí)現(xiàn)了說(shuō)中國(guó)話的接口 class Chinese implements SpeakChinese { public void shuoHua() { System.out.println("敲里嗎"); } }
// 適配器類(lèi),繼承了被適配類(lèi),同時(shí)實(shí)現(xiàn)標(biāo)準(zhǔn)接口 ——現(xiàn)在我們覺(jué)得,那個(gè)美國(guó)人說(shuō)的四字真言好拽哦,我也要學(xué)會(huì),于是我們定義了適配器 class Adapter extends American implements SpeakChinese { public void shuoHua() { super.speak(); } }測(cè)試
現(xiàn)在我們定義一個(gè)laoWang,老王是一個(gè)Chinese,他會(huì)說(shuō)話這個(gè)方法。
然后再定義一個(gè)適配器,看看適配器能不能用中文的說(shuō)話方法,說(shuō)出英文來(lái)。
// 測(cè)試類(lèi)public class Client { public static void main(String[] args) { // 使用普通功能類(lèi) SpeakChinese laoWang= new Chinese(); laoWang.shuoHua(); // 使用特殊功能類(lèi),即適配類(lèi) SpeakChinese adapter = new Adapter(); adapter.shuoHua(); } }
測(cè)試結(jié)果:
敲里嗎 f**k
很棒,現(xiàn)在用了適配器,適配器用說(shuō)中文的方式,說(shuō)出了這句著名的英文,現(xiàn)在我們迂回得到了說(shuō)這四個(gè)字母的能力,可以去找外國(guó)友人交流感情了。
對(duì)象適配器另外一種適配器模式是對(duì)象適配器,它不是使用多繼承或繼承再實(shí)現(xiàn)的方式,而是使用直接關(guān)聯(lián),或者稱為委托的方式。
具體實(shí)現(xiàn)其他目標(biāo)類(lèi)和被適配類(lèi)都一樣,就是適配器類(lèi)的定義方式有所不同:
// 適配器類(lèi),直接關(guān)聯(lián)被適配類(lèi),同時(shí)實(shí)現(xiàn)標(biāo)準(zhǔn)接口 class Adapter implements SpeakChinese { // 直接關(guān)聯(lián)被適配類(lèi) private American american; // 可以通過(guò)構(gòu)造函數(shù)傳入具體需要適配的被適配類(lèi)對(duì)象 public Adapter (American american) { this.american = american; } public void shuoHua() { // 這里是使用委托的方式完成特殊功能 this.american.speak(); } }測(cè)試
在這里,我們?yōu)榱烁`活一點(diǎn),定義了一個(gè)加州人,加州人和外面那些妖艷賤貨不一樣,他們比較優(yōu)雅,一般喜歡說(shuō)hello。
class Californian extends American{ public void speak() { System.out.println("hello"); } }
public class Client { public static void main(String[] args) { // 使用普通功能類(lèi) SpeakChinese laoWang = new Chinese(); laoWang.shuoHua(); // 使用特殊功能類(lèi),即適配類(lèi), // 需要先創(chuàng)建一個(gè)被適配類(lèi)的對(duì)象作為參數(shù) American tom = new Californian(){} Target adapter = new Adapter(tom); adapter.shuoHua(); } }
測(cè)試結(jié)果
敲里嗎 hello
同樣的,我們用適配器獲得了像加州人那樣優(yōu)雅的說(shuō)英文的能力。對(duì)象適配器相對(duì)于類(lèi)適配器來(lái)說(shuō)比較靈活,我們可以復(fù)用這個(gè)適配器,通過(guò)傳參的不同,得到德克薩斯人,弗吉尼亞人,佛羅里達(dá)人的說(shuō)話方式。
優(yōu)劣模式總結(jié)
優(yōu)點(diǎn)通過(guò)適配器,客戶端可以調(diào)用同一接口,因而對(duì)客戶端來(lái)說(shuō)是透明的。這樣做更簡(jiǎn)單、更直接、更緊湊。
復(fù)用了現(xiàn)存的類(lèi),解決了現(xiàn)存類(lèi)和復(fù)用環(huán)境要求不一致的問(wèn)題。
將目標(biāo)類(lèi)和適配者類(lèi)解耦,通過(guò)引入一個(gè)適配器類(lèi)重用現(xiàn)有的適配者類(lèi),而無(wú)需修改原有代碼。
一個(gè)對(duì)象適配器可以把多個(gè)不同的適配者類(lèi)適配到同一個(gè)目標(biāo),也就是說(shuō),同一個(gè)適配器可以把適配者類(lèi)和它的子類(lèi)都適配到目標(biāo)接口。
缺點(diǎn)過(guò)多的使用適配器,會(huì)讓系統(tǒng)非常零亂,不易整體進(jìn)行把握。比如,明明看到調(diào)用的是 A 接口,其實(shí)內(nèi)部被適配成了 B 接口的實(shí)現(xiàn),一個(gè)系統(tǒng)如果太多出現(xiàn)這種情況,無(wú)異于一場(chǎng)災(zāi)難。因此如果不是很有必要,可以不使用適配器,而是直接對(duì)系統(tǒng)進(jìn)行重構(gòu)。
2 策略模式 定義首先我們理解策略的概念,策略就是一組算法,一種實(shí)現(xiàn)。策略模式定義了一系列的算法,并將每一個(gè)算法封裝起來(lái),而且使他們可以相互替換,讓算法獨(dú)立于使用它的客戶而獨(dú)立變化。
本例使用場(chǎng)景例如神機(jī)妙算的諸葛亮,他的每個(gè)錦囊,就是一個(gè)策略,現(xiàn)在諸葛亮給了關(guān)羽三個(gè)錦囊——錦囊A,錦囊B,錦囊C,告訴關(guān)羽如果敵軍數(shù)量在一萬(wàn)到三萬(wàn)以內(nèi),打開(kāi)錦囊A;敵軍數(shù)量在三萬(wàn)到五萬(wàn)之間,打開(kāi)錦囊B;還更多的話,打開(kāi)錦囊C。
角色環(huán)境(Context)(具體策略的執(zhí)行者——關(guān)羽):持有一個(gè)Strategy的引用。
抽象策略(Strategy)(錦囊接口或者抽象類(lèi)):這是一個(gè)抽象角色,通常由一個(gè)接口或抽象類(lèi)實(shí)現(xiàn)。此角色給出所有的具體策略類(lèi)所需的接口。
具體策略(ConcreteStrategy)(具體的錦囊類(lèi)):包裝了相關(guān)的算法或行為。
具體實(shí)現(xiàn)//抽象策略類(lèi) 錦囊接口 public interface JinNang { /** * 策略方法 打開(kāi)錦囊 */ public void openJinNang(); }
//具體策略類(lèi) 錦囊A public class JinNangA implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("朝敵軍使用拋擲糞便攻擊,殺敵20%!傷敵數(shù)量為:"+enermyNum*0.2); } } //具體策略類(lèi) 錦囊B public class JinNangB implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("朝敵軍播放難忘今宵以瓦解敵軍意志,殺敵50%!傷敵數(shù)量為:"+enermyNum*0.5); } } //具體策略類(lèi) 錦囊C public class JinNangC implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("丫的還不快跑?。?); } }
//環(huán)境角色類(lèi)--關(guān)羽 public class GuanYu{ //持有一個(gè)具體策略的對(duì)象 private JinNang jinNang; /** * 策略方法 */ public void fight(Integer enermyNum){ if (enermyNum >10000&enermyNum<30000){ jinNang=new JinNangA(); } else if (enermyNum >30000&enermyNum<50000){ jinNang=new JinNangB(); } else{ jinNang=new JinNangC(); } jinNang.openJinNang(enermyNum); } }測(cè)試
好的,現(xiàn)在我們的關(guān)羽跨上赤兔馬,拎起青龍刀,來(lái)到了陣前,對(duì)面分別出動(dòng)了兩個(gè)師,四個(gè)師,十個(gè)師的兵力干他!即便如此,我們的小英雄也A了上去!
public static void main(String[] args) { GuanYu guanYu = new GuanYu(); guanYu.fight(20000); guanYu.fight(40000); guanYu.fight(100000); }
測(cè)試結(jié)果
顯而易見(jiàn),測(cè)試結(jié)果是:
朝敵軍使用拋擲糞便攻擊,殺敵20%!傷敵數(shù)量為:4000.0 朝敵軍播放難忘今宵以瓦解敵軍意志,殺敵50%!傷敵數(shù)量為:20000.0 丫的還不快跑???模式總結(jié)
策略模式的重心不是如何實(shí)現(xiàn)算法,而是如何組織、調(diào)用這些算法,從而讓程序結(jié)構(gòu)更靈活,具有更好的維護(hù)性和擴(kuò)展性。
運(yùn)行期間,策略模式在每一個(gè)時(shí)刻只能使用一個(gè)具體的策略實(shí)現(xiàn)對(duì)象,雖然可以動(dòng)態(tài)地在不同的策略實(shí)現(xiàn)中切換,但是同時(shí)只能使用一個(gè)。
優(yōu)劣 優(yōu)點(diǎn)策略模式提供了管理相關(guān)的算法族的辦法。策略類(lèi)的等級(jí)結(jié)構(gòu)定義了一個(gè)算法或行為族。恰當(dāng)使用繼承可以把公共的代碼移到父類(lèi)里面,從而避免代碼重復(fù)。
使用策略模式可以避免使用多重條件(if-else)語(yǔ)句。多重條件語(yǔ)句不易維護(hù),它把采取哪一種算法或采取哪一種行為的邏輯與算法或行為的邏輯混合在一起,統(tǒng)統(tǒng)列在一個(gè)多重條件語(yǔ)句里面,比使用繼承的辦法還要原始和落后。
缺點(diǎn)客戶端必須知道所有的策略類(lèi),并自行決定使用哪一個(gè)策略類(lèi)。這就意味著客戶端必須理解這些算法的區(qū)別,以便適時(shí)選擇恰當(dāng)?shù)乃惴?lèi)。換言之,策略模式只適用于客戶端知道算法或行為的情況。
由于策略模式把每個(gè)具體的策略實(shí)現(xiàn)都多帶帶封裝成為類(lèi),如果備選的策略很多的話,那么對(duì)象的數(shù)目就會(huì)很可觀。
3 外觀模式 定義外觀模式(Facade Pattern)又稱為門(mén)面模式,它為系統(tǒng)中的一組接口提供一個(gè)一致的界面,此模式定義了一個(gè)高層接口,這個(gè)接口使得子系統(tǒng)更加容易使用。該模式可以隱藏系統(tǒng)的復(fù)雜性,提供了客戶端請(qǐng)求的簡(jiǎn)化方法和對(duì)現(xiàn)有系統(tǒng)類(lèi)方法的委托調(diào)用。
本例使用場(chǎng)景蜀漢集團(tuán)總經(jīng)理諸葛亮為了光復(fù)中原,推出了“三個(gè)臭皮匠”陣法,由關(guān)羽張飛趙云壓陣,在砍人的時(shí)候充當(dāng)蜀軍的門(mén)面。于是在群P的時(shí)候,對(duì)于他們的客戶(敵人)來(lái)說(shuō),和外觀(陣法)交互(打架)并不需要知道他們內(nèi)在的細(xì)節(jié),許多繁瑣的邏輯,已經(jīng)被門(mén)面封裝了。
角色門(mén)面(facade)角色(三個(gè)臭皮匠陣法):外觀模式的核心。它被客戶角色調(diào)用,它熟悉子系統(tǒng)的功能。內(nèi)部根據(jù)客戶角色的需求預(yù)定了幾種功能的組合。
子系統(tǒng)(Subsystem)角色(關(guān)張趙三個(gè)子系統(tǒng)):子系統(tǒng)類(lèi),實(shí)現(xiàn)子系統(tǒng)的功能,處理外觀類(lèi)指派的任務(wù),注意子系統(tǒng)類(lèi)不含有外觀類(lèi)的引用。
具體實(shí)現(xiàn)我們先來(lái)定義三個(gè)子系統(tǒng):關(guān)張趙
/** * 子系統(tǒng)關(guān)羽 */ public class GuanYu { //剪刀 public void jianDao(){ System.out.println("關(guān)羽出剪刀"); } public void shiTou(){ System.out.println("關(guān)羽出石頭"); } public void bu(){ System.out.println("關(guān)羽出布"); } } /** * 子系統(tǒng)趙云 */ public class ZhaoYun{ //剪刀 public void jianDao(){ System.out.println("趙云出剪刀"); } public void shiTou(){ System.out.println("趙云出石頭"); } public void bu(){ System.out.println("趙云出布"); } } /** * 子系統(tǒng)張飛 */ public class ZhangFei { //剪刀 public void jianDao(){ System.out.println("張飛出剪刀"); } public void shiTou(){ System.out.println("張飛出石頭"); } public void bu(){ System.out.println("張飛出布"); } }
接下來(lái)定義統(tǒng)一的外觀類(lèi)——三個(gè)臭皮匠陣法,這個(gè)陣法有三個(gè)絕技,青龍騰,白龍騰和黑龍騰,至于技能內(nèi)到底怎么實(shí)現(xiàn)的,你們這些凡人就不要在意了,總之發(fā)動(dòng)起來(lái),天上都是龍,你們只要負(fù)責(zé)喊666就可以了。
public class ThreeChouPiJiang{ private GuanYu guanYu; private ZhangFei zhangFei; private ZhaoYun zhaoYun; ThreeChouPiJiang(){ guanYu =new GuanYu(); zhangFei = new ZhangFei(); zhaoYun = new ZhaoYun(); } //青龍騰 public void qingLongTeng(){ zhangFei.bu(); zhaoYun.bu(); guanYu.shiTou(); System.out.println("青龍騰:關(guān)羽輸了,關(guān)羽出去砍人;"); System.out.println("BO~BO~BO~經(jīng)費(fèi)燃燒中~ ============="); } //黑龍騰 public void heiLongTeng(){ guanYu.bu(); zhaoYun.bu(); zhangFei.shiTou(); System.out.println("黑龍騰:張飛輸了,張飛出去砍人;"); System.out.println("BO~BO~BO~經(jīng)費(fèi)燃燒中~ ============="); } //白龍騰 public void baiLongTeng(){ guanYu.bu(); zhangFei.bu(); zhaoYun.shiTou(); System.out.println(":趙云輸了,趙云出去砍人;"); System.out.println("BO~BO~BO~經(jīng)費(fèi)燃燒中~ ============="); } }測(cè)試
好了,我們的陣法已經(jīng)定義好了,現(xiàn)在諸葛亮意氣風(fēng)發(fā),決定要北伐中原,我們的三個(gè)臭皮匠陣法,開(kāi)始發(fā)揮威力:
public static void main(String[] args) { ThreeChouPiJiang threeChouPiJiang = new ThreeChouPiJiang(); ThreeChouPiJiang threeChouPiJiang = new ThreeChouPiJiang(); threeChouPiJiang.baiLongTeng(); threeChouPiJiang.qingLongTeng(); threeChouPiJiang.heiLongTeng(); }
測(cè)試結(jié)果:
關(guān)羽出布 張飛出布 趙云出石頭 白龍騰:趙云輸了,趙云出去砍人; BO~BO~BO~經(jīng)費(fèi)燃燒中~ ============= 張飛出布 趙云出布 關(guān)羽出石頭 青龍騰:關(guān)羽輸了,關(guān)羽出去砍人; BO~BO~BO~經(jīng)費(fèi)燃燒中~ ============= 關(guān)羽出布 趙云出布 張飛出石頭 黑龍騰:張飛輸了,張飛出去砍人; BO~BO~BO~經(jīng)費(fèi)燃燒中~ =============
威力果然是十分驚人??!對(duì)于敵人而言,他們只知道三個(gè)臭皮匠陣法使用了絕招,根本不會(huì)知道絕招內(nèi)部居然是這三個(gè)貨用剪刀石頭布搞出來(lái)的。在頂級(jí)特效的加持下,這個(gè)門(mén)面還是十分整潔十分威風(fēng)十分唬人的。
模式總結(jié)外觀模式的目的不是給予子系統(tǒng)添加新的功能接口,而是為了讓外部減少與子系統(tǒng)內(nèi)多個(gè)模塊的交互,松散耦合,從而讓外部能夠更簡(jiǎn)單地使用子系統(tǒng)。
外觀模式的本質(zhì)是:封裝交互,簡(jiǎn)化調(diào)用。
松散耦合,使得客戶端和子系統(tǒng)之間解耦,讓子系統(tǒng)內(nèi)部的模塊功能更容易擴(kuò)展和維護(hù);
簡(jiǎn)單易用,客戶端根本不需要知道子系統(tǒng)內(nèi)部的實(shí)現(xiàn),或者根本不需要知道子系統(tǒng)內(nèi)部的構(gòu)成,它只需要跟Facade類(lèi)交互即可。
更好的劃分訪問(wèn)層次,有些方法是對(duì)系統(tǒng)外的,有些方法是系統(tǒng)內(nèi)部相互交互的使用的。子系統(tǒng)把那些暴露給外部的功能集中到門(mén)面中,這樣就可以實(shí)現(xiàn)客戶端的使用,很好的隱藏了子系統(tǒng)內(nèi)部的細(xì)節(jié)。
缺點(diǎn)在不引入抽象外觀類(lèi)的情況下,增加新的子系統(tǒng)可能需要修改外觀類(lèi)或客戶端的源代碼,違背了“開(kāi)閉原則”
4 觀察者模式 定義在對(duì)象之間定義了一對(duì)多的依賴,這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài),依賴它的對(duì)象會(huì)收到通知并自動(dòng)更新。
簡(jiǎn)單來(lái)說(shuō),其實(shí)就是發(fā)布訂閱模式,發(fā)布者發(fā)布信息,訂閱者獲取信息,訂閱了就能收到信息,沒(méi)訂閱就收不到信息。
例如微信公眾號(hào)服務(wù),不定時(shí)發(fā)布一些消息,關(guān)注公眾號(hào)就可以收到推送消息,取消關(guān)注就收不到推送消息。
角色抽象被觀察者(公眾號(hào)接口):也就是一個(gè)抽象主題,它把所有對(duì)觀察者對(duì)象的引用保存在一個(gè)集合中,每個(gè)主題都可以有任意數(shù)量的觀察者。抽象主題提供一個(gè)接口,可以增加和刪除觀察者角色。一般用一個(gè)抽象類(lèi)和接口來(lái)實(shí)現(xiàn)。
抽象觀察者(訂閱人接口):為所有的具體觀察者定義一個(gè)接口,在得到主題通知時(shí)更新自己。
具體被觀察者(公眾號(hào)):也就是一個(gè)具體的主題,在集體主題的內(nèi)部狀態(tài)改變時(shí),所有登記過(guò)的觀察者發(fā)出通知。
具體觀察者(訂閱人):實(shí)現(xiàn)抽象觀察者角色所需要的更新接口,一邊使本身的狀態(tài)與制圖的狀態(tài)相協(xié)調(diào)。
具體實(shí)現(xiàn)/*** * 抽象被觀察者接口 * 聲明了添加、刪除、通知觀察者方法 */ public interface Observerable { public void registerObserver(Observer o);//新增訂閱人 public void removeObserver(Observer o);//刪除訂閱人 public void notifyObserver();//發(fā)布消息 }
/*** * 抽象觀察者 * 定義了一個(gè)update()方法,當(dāng)被觀察者調(diào)用notifyObservers()方法時(shí),觀察者的update()方法會(huì)被回調(diào)。 */ public interface Observer { public void update(String message);//更新消息 }
/** * 被觀察者,也就是微信公眾號(hào)服務(wù) * 實(shí)現(xiàn)了Observerable接口,對(duì)Observerable接口的三個(gè)方法進(jìn)行了具體實(shí)現(xiàn) */ public class WechatServer implements Observerable { //注意到這個(gè)List集合的泛型參數(shù)為Observer接口,設(shè)計(jì)原則:面向接口編程而不是面向?qū)崿F(xiàn)編程 private Listlist; private String message; public WechatServer() { list = new ArrayList (); } @Override public void registerObserver(Observer o) { list.add(o); } @Override public void removeObserver(Observer o) { if(!list.isEmpty()) list.remove(o); } //遍歷通知 @Override public void notifyObserver() { for(int i = 0; i < list.size(); i++) { Observer oserver = list.get(i); oserver.update(message); } } public void setInfomation(String s) { this.message = s; System.out.println("微信服務(wù)更新消息: " + s); //消息更新,通知所有觀察者 notifyObserver(); } }
/** * 觀察者 * 實(shí)現(xiàn)了update方法 */ public class User implements Observer { private String name; private String message; public User(String name) { this.name = name; } @Override public void update(String message) { this.message = message; read(); } public void read() { System.out.println(name + " 收到推送消息: " + message); } }測(cè)試
首先注冊(cè)了三個(gè)用戶,ZhangSan、LiSi、WangWu。公眾號(hào)發(fā)布了一條消息"PHP是世界上最好用的語(yǔ)言!",三個(gè)用戶都收到了消息。
用戶ZhangSan看到消息后頗為震驚,果斷取消訂閱,這時(shí)公眾號(hào)又推送了一條消息,此時(shí)用戶ZhangSan已經(jīng)收不到消息,其他用戶
還是正常能收到推送消息。
public class Test { public static void main(String[] args) { WechatServer server = new WechatServer(); Observer userZhang = new User("ZhangSan"); Observer userLi = new User("LiSi"); Observer userWang = new User("WangWu"); server.registerObserver(userZhang); server.registerObserver(userLi); server.registerObserver(userWang); server.setInfomation("PHP是世界上最好用的語(yǔ)言!"); System.out.println("----------------------------------------------"); server.removeObserver(userZhang); server.setInfomation("JAVA是世界上最好用的語(yǔ)言!"); } }
測(cè)試結(jié)果:
使多個(gè)對(duì)象都有機(jī)會(huì)處理同一個(gè)請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系。將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理它為止。
為完成同一個(gè)請(qǐng)求,如果存在多個(gè)請(qǐng)求處理器以及未知請(qǐng)求處理器個(gè)數(shù)或者請(qǐng)求處理器可動(dòng)態(tài)配置的情況下,可以考慮使用責(zé)任鏈模式。
適用于: 鏈條式處理事情。工作流程化、消息處理流程化、事物流程化;
本例使用場(chǎng)景圣斗士星矢,五小強(qiáng)們勇闖黃金十二宮,我們可以把這十二宮,看成是十二個(gè)處理者,他們用一條鏈串起來(lái)。
角色Handler抽象處理者(黃金圣斗士): 定義一個(gè)處理請(qǐng)求的接口,提供對(duì)后續(xù)處理者的引用
ConcreteHandler具體處理者(如白羊座圣斗士): 抽象處理者的子類(lèi),處理用戶請(qǐng)求,可選將請(qǐng)求處理掉還是傳給下家;在具體處理者中可以訪問(wèn)鏈中下一個(gè)對(duì)象,以便請(qǐng)求的轉(zhuǎn)發(fā)。
具體實(shí)現(xiàn)我們先來(lái)定義一個(gè)抽象的黃金圣斗士的抽象類(lèi):
public interface GoldenWarrior { void fight(String xiaoQiangName,String response,GoldenWarriorChain chain); }
我們定義一個(gè)白羊座圣斗士:
public class AriesWorrior implements GoldenWarrior{ @Override public void fight(String request, String response, GoldenWarriorChain chain) { System.out.println(request+"fight with AriesWorrior,AriesWorrior lose"); chain.fight(request, response, chain); System.out.println(response+" reback to AriesWorrior here!"); } }
再來(lái)定義一個(gè)獅子座圣斗士
public class LeoWorrior implements GoldenWarrior{ @Override public void fight(String request, String response, GoldenWarriorChain chain) { System.out.println(request+"fight with LeoWorrior,LeoWorrior lose"); chain.fight(request, response, chain); System.out.println(response+" reback to LeoWorrior here!"); } }
然后,是我們的責(zé)任鏈對(duì)象,或者說(shuō)是我們例子里面的 十二宮(其實(shí)我們就實(shí)現(xiàn)了兩宮)對(duì)象
public class GoldenWarriorChain implements GoldenWarrior{ //十二宮的圣斗士們 private List測(cè)試goldenWarriors=new ArrayList (); //目前到哪個(gè)宮了 private int index; public GoldenWarriorChain addWorrior(GoldenWarrior warrior){ this.goldenWarriors.add(warrior); return this; } public void fight(String request, String response,GoldenWarriorChain chain) { if(index==goldenWarriors.size()) return;//如果鏈條里沒(méi)有filter或是鏈條里的filter都調(diào)用過(guò)了(有點(diǎn)象遞歸) goldenWarriors.get(index++).fight(request, response, chain); } }
public static void main(String[] a){ GoldenWarriorChain goldenWarriorChain = new GoldenWarriorChain(); goldenWarriorChain.addWorrior(new LeoWorrior()); goldenWarriorChain.addWorrior(new AriesWorrior()); goldenWarriorChain.fight("星矢","",goldenWarriorChain); }結(jié)果
星矢fight with LeoWorrior,LeoWorrior lose 星矢fight with AriesWorrior,AriesWorrior lose reback to AriesWorrior here! reback to LeoWorrior here!
因?yàn)镾tring是不可變對(duì)象,故而,response和request沒(méi)能在調(diào)用后被自動(dòng)傳遞至下一層,或者遞歸后被自動(dòng)帶回上一層(實(shí)際上我們也沒(méi)有對(duì)它進(jìn)行過(guò)處理,只是打印出來(lái)而已),如果response和request是對(duì)象的話,上層對(duì)象就能得到下層的結(jié)果,不過(guò)我們的核心在不在這,無(wú)足輕重。
優(yōu)缺點(diǎn) 優(yōu)點(diǎn):1。責(zé)任的分擔(dān)。每個(gè)類(lèi)只需要處理自己該處理的工作(不該處理的傳遞給下一個(gè)對(duì)象完成),明確各類(lèi)的責(zé)任范圍,符合類(lèi)的最小封裝原則。
2??梢愿鶕?jù)需要自由組合工作流程。如工作流程發(fā)生變化,可以通過(guò)重新分配對(duì)象鏈便可適應(yīng)新的工作流程。
3。類(lèi)與類(lèi)之間可以以松耦合的形式加以組織。
因?yàn)樘幚頃r(shí)以鏈的形式在對(duì)象間傳遞消息,根據(jù)實(shí)現(xiàn)方式不同,有可能會(huì)影響處理的速度。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/69087.html
摘要:我們團(tuán)隊(duì)在屏幕直播方案掘金項(xiàng)目需求是實(shí)時(shí)同步手機(jī)屏幕畫(huà)面至瀏覽器。由于引入了對(duì)框架的重大改進(jìn),因此只有通過(guò)支持庫(kù)的讓所有以上的設(shè)上如何實(shí)現(xiàn)矩形區(qū)域截屏掘金對(duì)屏幕進(jìn)行截屏并裁剪有兩種方式早截圖和晚截圖。 從框架層分析如何啟動(dòng)未注冊(cè)的 Activity - Android - 掘金本文關(guān)鍵詞:Binder、AMS、ActivityThread、Handler、Java 反射 引言要解決這個(gè)...
摘要:模式工廠模式構(gòu)造器模式通過(guò)對(duì)象實(shí)現(xiàn)模式構(gòu)造器與原型方式的混合模式動(dòng)態(tài)原型模式混合工廠模式模式字面量的表現(xiàn)形式等價(jià)于即以對(duì)象為一個(gè)原型模板新建一個(gè)以這個(gè)原型模板為原型的對(duì)象區(qū)別創(chuàng)建一個(gè)原型為的對(duì)象在里查看各個(gè)新建對(duì)象的區(qū)別可以看出前種模式創(chuàng)建 Objct 模式 工廠模式 構(gòu)造器模式 通過(guò) Function 對(duì)象實(shí)現(xiàn) prototype 模式 構(gòu)造器與原型方式的混合模式 動(dòng)態(tài)原型模式 混...
摘要:反正就是相反的意思了異或當(dāng)兩者中只有一個(gè)那么結(jié)果才為。將指定根據(jù)的標(biāo)識(shí)轉(zhuǎn)換成為進(jìn)制。當(dāng)創(chuàng)建實(shí)例的構(gòu)造函數(shù)時(shí),內(nèi)部會(huì)同時(shí)創(chuàng)建一個(gè)用來(lái)作為數(shù)據(jù)的存儲(chǔ)。不過(guò),根據(jù)上面的構(gòu)造函數(shù)上看,其實(shí),可以將一整個(gè)拆成不同的進(jìn)行讀取。 Web 進(jìn)制操作是一個(gè)比較底層的話題,因?yàn)槠匠W鰳I(yè)務(wù)的時(shí)候根本用不到太多,或者說(shuō),根本用不到。 老鐵,沒(méi)毛病 那什么情況會(huì)用到呢? canvas websocket fi...
閱讀 3948·2021-11-18 13:19
閱讀 1182·2021-10-11 10:58
閱讀 3292·2019-08-29 16:39
閱讀 3146·2019-08-26 12:08
閱讀 2038·2019-08-26 11:33
閱讀 2461·2019-08-23 18:30
閱讀 1309·2019-08-23 18:21
閱讀 2522·2019-08-23 18:18