最近加班是真的不少,沒法騰出大塊時間來學習。設計模式又不想只更到一半半途而廢,想了又想,決定精簡,保證你們一看就懂(看完就忘...)。設計模式分建立型模式,結構型模式和行爲型模式。到目前爲止,建立型模式已經講完,對於剩下的模式,會分紅這兩大塊統一講解。算法
行爲型模式主要關注的點事類的動做,各個類之間相互的做用,將職責劃分清楚,使咱們的代碼更加的清晰。數據庫
定義一組算法,將每一個算法都封裝起來,而且使他們之間能夠互換。
策略模式是一個出現頻率很高,但又很簡單的模式。下面的場景是咱們要出去旅遊,可是能夠選擇出去旅遊的交通方式,好比坐飛機,坐火車或者步行。廢話再也不多說,直接上碼:
public interface Strategy { void travel(); }
public class Walk implements Strategy { @Override public void travel() { System.out.println("步行去旅行"); } }
public class Train implements Strategy { @Override public void travel() { System.out.println("坐火車去旅行"); } }
public class Airplane implements Strategy { @Override public void travel() { System.out.println("坐着飛機去旅行"); } }
public class Context { private Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } public void execute(){ strategy.travel(); } }
public class Client { public static void main(String[] args) { Context context = new Context(new Airplane()); context.execute(); } } console: 坐着飛機去旅行
策略模式的優勢很是明顯,在現有的系統中增長一個策略太容易,只要實現接口就能夠了,其餘都不用修改,相似於一個能夠反覆拆卸的插件,符合ocp原則。其缺點就是每一個策略都是一個類,複用性很小,複雜的業務場景容易發生類數量爆炸,而且策略模式和迪米特法則是違背的,咱們看下上面的clent場景類(至關於項目中的高層調用模塊),我只是想使用一個策略,憑什麼就要了解這個策略呢?那要封裝類就沒有意義了,這是策略模式的一個大缺點,因此策略模式不多單獨出現,大多結合其餘模式來彌補這個缺陷,如工廠方法或者代理模式。segmentfault
定義對象間一種一對多的依賴關係,使得每當一個對象改變狀態,則全部依賴於它的對象都會獲得通知並被自動更新
策略模式也叫發佈訂閱模式,其中最主要額角色名稱就是subject被觀察者和observer觀察者。接下來會模擬一個場景,學校做爲被觀察者發佈放假的消息,家長和學生做爲觀察者實現本身的邏輯:設計模式
/** * 主題(被觀察者)須要實現的職責,就是能夠動態的增長刪除觀察者。 * 根據主題的狀態通知全部的觀察者Observer */ public abstract class Subject { private Vector<Observer> observerList = new Vector<>(); private int status; public void addObserver(Observer observer){ observerList.add(observer); } public void delObserver(Observer observer){ observerList.remove(observer); } public void notifyAllObserver(){ observerList.forEach(observer -> { observer.update(); }); } }
public class SchoolSubject extends Subject { //學校宣佈放七天假期 public void haveSevenDaysHoliday(){ System.out.println("學校:從今天開始放假,全部學生七天後返校"); super.notifyAllObserver(); } }
public interface Observer { //觀察者,被通知了實現其本身的邏輯 void update() ; }
public class Parent implements Observer { @Override public void update() { System.out.println("家長:這倒黴孩子怎麼又放假了,堅定不能讓他玩王者榮耀...."); } }
public class Student implements Observer { @Override public void update() { System.out.println("學生:哇哈哈,終於有時間打王者榮耀嘍"); } }
public class Client { public static void main(String[] args) { SchoolSubject subject = new SchoolSubject(); Student student = new Student(); Parent parent = new Parent(); subject.addObserver(student); subject.addObserver(parent); subject.haveSevenDaysHoliday(); } } console: 學校:從今天開始放假,全部學生七天後返校 學生:哇哈哈,終於有時間打王者榮耀嘍 家長:這倒黴孩子怎麼又放假了,堅定不能讓他玩王者榮耀....
雖然說觀察者和被觀察者是耦合在一塊兒的,可是不論是擴展增長觀察者仍是被觀察者都很是容易。而且根據單一職責原則,每一個類的職責都是惟一,須要一套機制將類串聯起來造成一個真實的場景,就好比學校公佈放假,孩子想着玩遊戲,家長爲了孩子的成績禁止孩子玩遊戲,而後由於學校放假我就不玩了(小學生,你懂得),這樣就造成了一個觸發機制。其缺點就是執行效率低下,需異步執行。從原理上看,咱們經常使用的mq就是觀察者模式的升級版。異步
使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有對象處理它爲止。
責任鏈咱們很容易想到鏈表結構,實際上責任鏈就是一種基於鏈表的處理方式。當一個請求過來,調用鏈表的頭結點,處理以後再日後流轉。
有這麼一個場景:路飛餓了打開美團準備訂外賣。選中吃的後,進行下單,首先校驗是否在營業時間內,而後校驗是否在配送範圍內,而後校驗是否有貨等等,設定責任鏈都經過後,路飛才能訂到飯。ide
//鏈表內結點的基類 public abstract class RuleHandler { protected RuleHandler successor; public abstract void echo(Context context); public void setSuccessor(RuleHandler successor) { this.successor = successor; } public RuleHandler getSuccessor() { return successor; } }
//判斷營業時間 public class TimeHandler extends RuleHandler { @Override public void echo(Context context) { //營業時間判斷 if (context.isTimeInRange()){ if (this.getSuccessor()!=null){ this.getSuccessor().echo(context); } }else { throw new RuntimeException("不在營業時間內"); } } }
//判斷是否在配送範圍內 public class AreaHanler extends RuleHandler { @Override public void echo(Context context) { if (context.isAreaInRange()){ if (this.getSuccessor()!=null){ this.getSuccessor().echo(context); } }else { throw new RuntimeException("不在配送範圍內"); } } }
//判斷庫存 public class StockHandler extends RuleHandler { @Override public void echo(Context context) { if (context.hasStock()){ if (this.getSuccessor()!=null){ this.getSuccessor().echo(context); } }else { throw new RuntimeException("挑選的商品已經賣完"); } } }
客戶端調用邏輯:性能
public class Client { public static void main(String[] args) { RuleHandler timeHandler = new TimeHandler(); RuleHandler areaHandler = new AreaHanler(); RuleHandler stockHandler = new StockHandler(); timeHandler.setSuccessor(areaHandler); areaHandler.setSuccessor(stockHandler); timeHandler.echo(new Context()); } }
代碼很是簡單,責任鏈模式的重點是在鏈上,由一條鏈去處理請求並返回相應的結果。它很是顯著的優勢就是將請求和處理分開,二者解耦,提升系統的靈活性。缺點就是鏈表遍歷必須從鏈頭到鏈尾,存在性能問題。採用了相似遞歸調用的方式,增大了讀懂邏輯的難度學習
在以前的博客裏已經長篇大論過,故直接拿過來。
模板方法測試
當一個對象內在狀態改變時容許其改變行爲,這個對象看起來像改變了其類。
狀態模式的核心是封裝,經過狀態的變動引發行爲的變動。如今你們來思考一下,電腦有三種狀態,分別爲關機,已啓動。this
//表明環境,也就是狀態的主體 public class Context { //全部的電腦狀態 public final static OpenState OPEN = new OpenState(); public final static CloseState CLOSE = new CloseState(); //電腦當前的狀態 private ComputerState currentState; public ComputerState getCurrentState() { return currentState; } public void setCurrentState(ComputerState currentState) { this.currentState = currentState; this.currentState.setContext(this); } public void openMachine() { this.currentState.openMachine(); } public void closeMachine() { this.currentState.closeMachine(); } }
//狀態基類,真實的電腦邏輯封裝在了狀態中 public abstract class ComputerState { protected Context context; public void setContext(Context context) { this.context = context; } public abstract void openMachine(); public abstract void closeMachine(); }
public class OpenState extends ComputerState{ @Override public void openMachine() { System.out.println("電腦開機..."); } @Override public void closeMachine() { super.context.setCurrentState(Context.CLOSE); super.context.getCurrentState().closeMachine(); } }
public class CloseState extends ComputerState { @Override public void openMachine() { super.context.setCurrentState(Context.OPEN); super.context.getCurrentState().openMachine(); } @Override public void closeMachine() { System.out.println("電腦關機..."); } }
客戶端測試類:
public class Client { public static void main(String[] args) { Context context = new Context(); context.setCurrentState(Context.OPEN); context.openMachine(); context.closeMachine(); } }
狀態模式的優勢有結構清晰,避免了各類條件的判斷,省掉了swtich...case,if...else語句的使用,提高了代碼的可讀性。遵循了單一職責原則和開閉原則,每一個狀態都是一個子類,增長狀態只需增長一個狀態子類,修改狀態,修改對應的子類就能夠了。封裝性很是好,客戶端不需知道內部狀態的轉換以及相應的邏輯.其缺點就是狀態子類會太多,而且咱們能夠將狀態存儲到數據庫中,而後根據狀態執行相應的操做,這也是一種不錯的實現方式,具體如何使用看你們我的喜愛了。
本章的行爲型模式總結了策略模式、觀察者模式、責任鏈模式、模板方法模式和狀態模式,其實不只於此,還有備忘錄模式和命令模式等,但因其使用場景有限,就不作一一探討了,留給讀者本身學習~.~