這些設計模式提供了一種在建立對象的同時隱藏建立邏輯的方式,而不是使用新的運算符直接實例化對象。這使得程序在判斷針對某個給定實例須要建立哪些對象時更加靈活。算法
這些設計模式關注類和對象的組合。繼承的概念被用來組合接口和定義組合對象得到新功能的方式。編程
這些設計模式特別關注對象之間的通訊。設計模式
將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠在一塊兒工做。
咱們用圖來形象的解釋這一律念:微信
這裏的重點在於,老接口有特殊功能,咱們不忍捨棄,好比只有歐洲的插頭(老接口)能從插座裏得到電,沒有電咱們過不下去。這個功能咱們沒法捨棄
爲了繼續享受這個特殊功能,咱們使用適配器模式,讓咱們手中的美國的插頭(新接口),擁有老接口的能力。ide
例如一個美國人說英語,一箇中國人說中文,爲了跟美國人作生意,說英文這個功能咱們沒法捨棄,可是咱們是中國人,天生不會說英文。因而二者想要交流,就須要一個適配器,來充當溝通二者的工做。如今,咱們但願讓一個能說中國話的個體(實現說中文的接口的類),開口說英文。函數
適配器有兩種主要的實現,咱們先看第一種——類適配器測試
// 被適配類,已存在的、具備還有用處的特殊功能、但不符合咱們既有的標準接口的類 //——本例中即爲一個會說f**k的美國人(你能夠看做這個美國人實現了說英文的接口,不過這個可有可無,省略),他說的話咱們聽不懂 class American{ public void speak() { System.out.println("f**k"); } }
// 目標接口,或稱爲標準接口 ——這裏是一個說中文能力的接口,他定義了方法「說話」。 interface SpeakChinese { public void shuoHua(); }
// 具體目標類,只提供普通功能 ——這裏咱們的具體實現是一箇中國人類,他實現了說中國話的接口 class Chinese implements SpeakChinese { public void shuoHua() { System.out.println("敲裏嗎"); } }
// 適配器類,繼承了被適配類,同時實現標準接口 ——如今咱們以爲,那個美國人說的四字真言好拽哦,我也要學會,因而咱們定義了適配器 class Adapter extends American implements SpeakChinese { public void shuoHua() { super.speak(); } }
如今咱們定義一個laoWang,老王是一個Chinese,他會說話這個方法。
而後再定義一個適配器,看看適配器能不能用中文的說話方法,說出英文來。ui
// 測試類public class Client { public static void main(String[] args) { // 使用普通功能類 SpeakChinese laoWang= new Chinese(); laoWang.shuoHua(); // 使用特殊功能類,即適配類 SpeakChinese adapter = new Adapter(); adapter.shuoHua(); } }
測試結果:this
敲裏嗎 f**k
很棒,如今用了適配器,適配器用說中文的方式,說出了這句著名的英文,如今咱們迂迴獲得了說這四個字母的能力,能夠去找外國友人交流感情了。spa
另一種適配器模式是對象適配器,它不是使用多繼承或繼承再實現的方式,而是使用直接關聯,或者稱爲委託的方式。
其餘目標類和被適配類都同樣,就是適配器類的定義方式有所不一樣:
// 適配器類,直接關聯被適配類,同時實現標準接口 class Adapter implements SpeakChinese { // 直接關聯被適配類 private American american; // 能夠經過構造函數傳入具體須要適配的被適配類對象 public Adapter (American american) { this.american = american; } public void shuoHua() { // 這裏是使用委託的方式完成特殊功能 this.american.speak(); } }
在這裏,咱們爲了更靈活一點,定義了一個加州人,加州人和外面那些妖豔賤貨不同,他們比較優雅,通常喜歡說hello。
class Californian extends American{ public void speak() { System.out.println("hello"); } }
public class Client { public static void main(String[] args) { // 使用普通功能類 SpeakChinese laoWang = new Chinese(); laoWang.shuoHua(); // 使用特殊功能類,即適配類, // 須要先建立一個被適配類的對象做爲參數 American tom = new Californian(){} Target adapter = new Adapter(tom); adapter.shuoHua(); } }
測試結果
敲裏嗎 hello
一樣的,咱們用適配器得到了像加州人那樣優雅的說英文的能力。對象適配器相對於類適配器來講比較靈活,咱們能夠複用這個適配器,經過傳參的不一樣,獲得德克薩斯人,弗吉尼亞人,佛羅里達人的說話方式。
模式總結
首先咱們理解策略的概念,策略就是一組算法,一種實現。策略模式定義了一系列的算法,並將每個算法封裝起來,並且使他們能夠相互替換,讓算法獨立於使用它的客戶而獨立變化。
例如足智多謀的諸葛亮,他的每一個錦囊,就是一個策略,如今諸葛亮給了關羽三個錦囊——錦囊A,錦囊B,錦囊C,告訴關羽若是敵軍數量在一萬到三萬之內,打開錦囊A;敵軍數量在三萬到五萬之間,打開錦囊B;還更多的話,打開錦囊C。
//抽象策略類 錦囊接口 public interface JinNang { /** * 策略方法 打開錦囊 */ public void openJinNang(); }
//具體策略類 錦囊A public class JinNangA implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("朝敵軍使用拋擲糞便攻擊,殺敵20%!傷敵數量爲:"+enermyNum*0.2); } } //具體策略類 錦囊B public class JinNangB implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("朝敵軍播放難忘今宵以瓦解敵軍意志,殺敵50%!傷敵數量爲:"+enermyNum*0.5); } } //具體策略類 錦囊C public class JinNangC implements JinNang { @Override public void openJinNang(Integer enermyNum) { System.out.println("丫的還不快跑!?"); } }
//環境角色類--關羽 public class GuanYu{ //持有一個具體策略的對象 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); } }
好的,如今咱們的關羽跨上赤兔馬,拎起青龍刀,來到了陣前,對面分別出動了兩個師,四個師,十個師的兵力幹他!即使如此,咱們的小英雄也A了上去!
public static void main(String[] args) { GuanYu guanYu = new GuanYu(); guanYu.fight(20000); guanYu.fight(40000); guanYu.fight(100000); }
測試結果
顯而易見,測試結果是:
朝敵軍使用拋擲糞便攻擊,殺敵20%!傷敵數量爲:4000.0 朝敵軍播放難忘今宵以瓦解敵軍意志,殺敵50%!傷敵數量爲:20000.0 丫的還不快跑!?
外觀模式(Facade Pattern)又稱爲門面模式,它爲系統中的一組接口提供一個一致的界面,此模式定義了一個高層接口,這個接口使得子系統更加容易使用。該模式能夠隱藏系統的複雜性,提供了客戶端請求的簡化方法和對現有系統類方法的委託調用。
蜀漢集團總經理諸葛亮爲了光復中原,推出了「三個臭皮匠」陣法,由關羽張飛趙雲壓陣,在砍人的時候充當蜀軍的門面。因而在羣P的時候,對於他們的客戶(敵人)來講,和外觀(陣法)交互(打架)並不須要知道他們內在的細節,許多繁瑣的邏輯,已經被門面封裝了。
咱們先來定義三個子系統:關張趙
/** * 子系統關羽 */ public class GuanYu { //剪刀 public void jianDao(){ System.out.println("關羽出剪刀"); } public void shiTou(){ System.out.println("關羽出石頭"); } public void bu(){ System.out.println("關羽出布"); } } /** * 子系統趙雲 */ public class ZhaoYun{ //剪刀 public void jianDao(){ System.out.println("趙雲出剪刀"); } public void shiTou(){ System.out.println("趙雲出石頭"); } public void bu(){ System.out.println("趙雲出布"); } } /** * 子系統張飛 */ public class ZhangFei { //剪刀 public void jianDao(){ System.out.println("張飛出剪刀"); } public void shiTou(){ System.out.println("張飛出石頭"); } public void bu(){ System.out.println("張飛出布"); } }
接下來定義統一的外觀類——三個臭皮匠陣法,這個陣法有三個絕技,青龍騰,白龍騰和黑龍騰,至於技能內到底怎麼實現的,大家這些凡人就不要在乎了,總之發動起來,天上都是龍,大家只要負責喊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("青龍騰:關羽輸了,關羽出去砍人;"); System.out.println("BO~BO~BO~經費燃燒中~ ============="); } //黑龍騰 public void heiLongTeng(){ guanYu.bu(); zhaoYun.bu(); zhangFei.shiTou(); System.out.println("黑龍騰:張飛輸了,張飛出去砍人;"); System.out.println("BO~BO~BO~經費燃燒中~ ============="); } //白龍騰 public void baiLongTeng(){ guanYu.bu(); zhangFei.bu(); zhaoYun.shiTou(); System.out.println(":趙雲輸了,趙雲出去砍人;"); System.out.println("BO~BO~BO~經費燃燒中~ ============="); } }
好了,咱們的陣法已經定義好了,如今諸葛亮意氣風發,決定要北伐中原,咱們的三個臭皮匠陣法,開始發揮威力:
public static void main(String[] args) { ThreeChouPiJiang threeChouPiJiang = new ThreeChouPiJiang(); ThreeChouPiJiang threeChouPiJiang = new ThreeChouPiJiang(); threeChouPiJiang.baiLongTeng(); threeChouPiJiang.qingLongTeng(); threeChouPiJiang.heiLongTeng(); }
測試結果:
關羽出布 張飛出布 趙雲出石頭 白龍騰:趙雲輸了,趙雲出去砍人; BO~BO~BO~經費燃燒中~ ============= 張飛出布 趙雲出布 關羽出石頭 青龍騰:關羽輸了,關羽出去砍人; BO~BO~BO~經費燃燒中~ ============= 關羽出布 趙雲出布 張飛出石頭 黑龍騰:張飛輸了,張飛出去砍人; BO~BO~BO~經費燃燒中~ =============
威力果真是十分驚人啊!對於敵人而言,他們只知道三個臭皮匠陣法使用了絕招,根本不會知道絕招內部竟然是這三個貨用剪刀石頭布搞出來的。在頂級特效的加持下,這個門面仍是十分整潔十分威風十分唬人的。
外觀模式的目的不是給予子系統添加新的功能接口,而是爲了讓外部減小與子系統內多個模塊的交互,鬆散耦合,從而讓外部可以更簡單地使用子系統。
外觀模式的本質是:封裝交互,簡化調用。
在對象之間定義了一對多的依賴,這樣一來,當一個對象改變狀態,依賴它的對象會收到通知並自動更新。
簡單來講,其實就是發佈訂閱模式,發佈者發佈信息,訂閱者獲取信息,訂閱了就能收到信息,沒訂閱就收不到信息。
例如微信公衆號服務,不定時發佈一些消息,關注公衆號就能夠收到推送消息,取消關注就收不到推送消息。
/*** * 抽象被觀察者接口 * 聲明瞭添加、刪除、通知觀察者方法 */ public interface Observerable { public void registerObserver(Observer o);//新增訂閱人 public void removeObserver(Observer o);//刪除訂閱人 public void notifyObserver();//發佈消息 }
/*** * 抽象觀察者 * 定義了一個update()方法,當被觀察者調用notifyObservers()方法時,觀察者的update()方法會被回調。 */ public interface Observer { public void update(String message);//更新消息 }
/** * 被觀察者,也就是微信公衆號服務 * 實現了Observerable接口,對Observerable接口的三個方法進行了具體實現 */ public class WechatServer implements Observerable { //注意到這個List集合的泛型參數爲Observer接口,設計原則:面向接口編程而不是面向實現編程 private List<Observer> list; private String message; public WechatServer() { list = new ArrayList<Observer>(); } @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("微信服務更新消息: " + s); //消息更新,通知全部觀察者 notifyObserver(); } }
/** * 觀察者 * 實現了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); } }
首先註冊了三個用戶,ZhangSan、LiSi、WangWu。公衆號發佈了一條消息"PHP是世界上最好用的語言!",三個用戶都收到了消息。
用戶ZhangSan看到消息後頗爲震驚,果斷取消訂閱,這時公衆號又推送了一條消息,此時用戶ZhangSan已經收不到消息,其餘用戶
仍是正常能收到推送消息。
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是世界上最好用的語言!"); System.out.println("----------------------------------------------"); server.removeObserver(userZhang); server.setInfomation("JAVA是世界上最好用的語言!"); } }
測試結果:
使多個對象都有機會處理同一個請求,從而避免請求的發送者和接收者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。
爲完成同一個請求,若是存在多個請求處理器以及未知請求處理器個數或者請求處理器可動態配置的狀況下,能夠考慮使用責任鏈模式。
適用於: 鏈條式處理事情。工做流程化、消息處理流程化、事物流程化;
聖鬥士星矢,五小強們勇闖黃金十二宮,咱們能夠把這十二宮,當作是十二個處理者,他們用一條鏈串起來。
咱們先來定義一個抽象的黃金聖鬥士的抽象類:
public interface GoldenWarrior { void fight(String xiaoQiangName,String response,GoldenWarriorChain chain); }
咱們定義一個白羊座聖鬥士:
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!"); } }
再來定義一個獅子座聖鬥士
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!"); } }
而後,是咱們的責任鏈對象,或者說是咱們例子裏面的 十二宮(其實咱們就實現了兩宮)對象
public class GoldenWarriorChain implements GoldenWarrior{ //十二宮的聖鬥士們 private List<GoldenWarrior> goldenWarriors=new ArrayList<GoldenWarrior>(); //目前到哪一個宮了 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;//若是鏈條裏沒有filter或是鏈條裏的filter都調用過了(有點象遞歸) 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); }
星矢fight with LeoWorrior,LeoWorrior lose 星矢fight with AriesWorrior,AriesWorrior lose reback to AriesWorrior here! reback to LeoWorrior here!
由於String是不可變對象,故而,response和request沒能在調用後被自動傳遞至下一層,或者遞歸後被自動帶回上一層(實際上咱們也沒有對它進行過處理,只是打印出來而已),若是response和request是對象的話,上層對象就能獲得下層的結果,不過咱們的核心在不在這,無足輕重。
1。責任的分擔。每一個類只須要處理本身該處理的工做(不應處理的傳遞給下一個對象完成),明確各種的責任範圍,符合類的最小封裝原則。
2。能夠根據須要自由組合工做流程。如工做流程發生變化,能夠經過從新分配對象鏈即可適應新的工做流程。
3。類與類之間能夠以鬆耦合的形式加以組織。
由於處理時以鏈的形式在對象間傳遞消息,根據實現方式不一樣,有可能會影響處理的速度。