摘要:設(shè)計模式分創(chuàng)建型模式,結(jié)構(gòu)型模式和行為型模式。責(zé)任鏈模式使多個對象都有機(jī)會處理請求,從而避免了請求的發(fā)送者和接受者之間的耦合關(guān)系。狀態(tài)模式的核心是封裝,通過狀態(tài)的變更引起行為的變更。
前言
最近加班是真的很多,無法騰出大塊時間來學(xué)習(xí)。設(shè)計模式又不想只更到一半半途而廢,想了又想,決定精簡,保證大家一看就懂(看完就忘...)。設(shè)計模式分創(chuàng)建型模式,結(jié)構(gòu)型模式和行為型模式。到目前為止,創(chuàng)建型模式已經(jīng)講完,對于剩下的模式,會分成這兩大塊統(tǒng)一講解。
行為型模式行為型模式主要關(guān)注的點事類的動作,各個類之間相互的作用,將職責(zé)劃分清楚,使我們的代碼更加的清晰。
策略模式定義一組算法,將每個算法都封裝起來,并且使他們之間可以互換。
策略模式是一個出現(xiàn)頻率很高,但又很簡單的模式。下面的場景是我們要出去旅游,但是可以選擇出去旅游的交通方式,比如坐飛機(jī),坐火車或者步行。廢話不再多說,直接上碼:
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("坐著飛機(jī)去旅行"); } }
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: 坐著飛機(jī)去旅行
策略模式的優(yōu)點非常明顯,在現(xiàn)有的系統(tǒng)中增加一個策略太容易,只要實現(xiàn)接口就可以了,其他都不用修改,類似于一個可以反復(fù)拆卸的插件,符合ocp原則。其缺點就是每個策略都是一個類,復(fù)用性很小,復(fù)雜的業(yè)務(wù)場景容易發(fā)生類數(shù)量爆炸,并且策略模式和迪米特法則是違背的,我們看下上面的clent場景類(相當(dāng)于項目中的高層調(diào)用模塊),我只是想使用一個策略,憑什么就要了解這個策略呢?那要封裝類就沒有意義了,這是策略模式的一個大缺點,所以策略模式很少多帶帶出現(xiàn),大多結(jié)合其他模式來彌補(bǔ)這個缺陷,如工廠方法或者代理模式。
觀察者模式定義對象間一種一對多的依賴關(guān)系,使得每當(dāng)一個對象改變狀態(tài),則所有依賴于它的對象都會得到通知并被自動更新
策略模式也叫發(fā)布訂閱模式,其中最主要額角色名稱就是subject被觀察者和observer觀察者。接下來會模擬一個場景,學(xué)校作為被觀察者發(fā)布放假的消息,家長和學(xué)生作為觀察者實現(xiàn)自己的邏輯:
/** * 主題(被觀察者)需要實現(xiàn)的職責(zé),就是可以動態(tài)的增加刪除觀察者。 * 根據(jù)主題的狀態(tài)通知所有的觀察者Observer */ public abstract class Subject { private VectorobserverList = 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 { //學(xué)校宣布放七天假期 public void haveSevenDaysHoliday(){ System.out.println("學(xué)校:從今天開始放假,所有學(xué)生七天后返校"); super.notifyAllObserver(); } }
public interface Observer { //觀察者,被通知了實現(xiàn)其自己的邏輯 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("學(xué)生:哇哈哈,終于有時間打王者榮耀嘍"); } }
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: 學(xué)校:從今天開始放假,所有學(xué)生七天后返校 學(xué)生:哇哈哈,終于有時間打王者榮耀嘍 家長:這倒霉孩子怎么又放假了,堅決不能讓他玩王者榮耀....
雖說觀察者和被觀察者是耦合在一起的,但是不管是擴(kuò)展增加觀察者還是被觀察者都非常容易。并且根據(jù)單一職責(zé)原則,每個類的職責(zé)都是唯一,需要一套機(jī)制將類串聯(lián)起來形成一個真實的場景,就比如學(xué)校公布放假,孩子想著玩游戲,家長為了孩子的成績禁止孩子玩游戲,然后因為學(xué)校放假我就不玩了(小學(xué)生,你懂得),這樣就形成了一個觸發(fā)機(jī)制。其缺點就是執(zhí)行效率低下,需異步執(zhí)行。從原理上看,我們常用的mq就是觀察者模式的升級版。
責(zé)任鏈模式使多個對象都有機(jī)會處理請求,從而避免了請求的發(fā)送者和接受者之間的耦合關(guān)系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有對象處理它為止。
責(zé)任鏈我們很容易想到鏈表結(jié)構(gòu),實際上責(zé)任鏈就是一種基于鏈表的處理方式。當(dāng)一個請求過來,調(diào)用鏈表的頭結(jié)點,處理之后再往后流轉(zhuǎn)。
有這么一個場景:路飛餓了打開美團(tuán)準(zhǔn)備訂外賣。選中吃的后,進(jìn)行下單,首先校驗是否在營業(yè)時間內(nèi),然后校驗是否在配送范圍內(nèi),然后校驗是否有貨等等,設(shè)定責(zé)任鏈都通過后,路飛才能訂到飯。
//鏈表內(nèi)結(jié)點的基類 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; } }
//判斷營業(yè)時間 public class TimeHandler extends RuleHandler { @Override public void echo(Context context) { //營業(yè)時間判斷 if (context.isTimeInRange()){ if (this.getSuccessor()!=null){ this.getSuccessor().echo(context); } }else { throw new RuntimeException("不在營業(yè)時間內(nèi)"); } } }
//判斷是否在配送范圍內(nèi) 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("不在配送范圍內(nèi)"); } } }
//判斷庫存 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("挑選的商品已經(jīng)賣完"); } } }
客戶端調(diào)用邏輯:
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()); } }
代碼非常簡單,責(zé)任鏈模式的重點是在鏈上,由一條鏈去處理請求并返回相應(yīng)的結(jié)果。它非常顯著的優(yōu)點就是將請求和處理分開,兩者解耦,提高系統(tǒng)的靈活性。缺點就是鏈表遍歷必須從鏈頭到鏈尾,存在性能問題。采用了類似遞歸調(diào)用的方式,增大了讀懂邏輯的難度
模板方法模式在之前的博客里已經(jīng)長篇大論過,故直接拿過來。
模板方法
當(dāng)一個對象內(nèi)在狀態(tài)改變時允許其改變行為,這個對象看起來像改變了其類。
狀態(tài)模式的核心是封裝,通過狀態(tài)的變更引起行為的變更?,F(xiàn)在大家來思考一下,電腦有三種狀態(tài),分別為關(guān)機(jī),已啟動。
//代表環(huán)境,也就是狀態(tài)的主體 public class Context { //所有的電腦狀態(tài) public final static OpenState OPEN = new OpenState(); public final static CloseState CLOSE = new CloseState(); //電腦當(dāng)前的狀態(tài) 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(); } }
//狀態(tài)基類,真實的電腦邏輯封裝在了狀態(tài)中 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("電腦開機(jī)..."); } @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("電腦關(guān)機(jī)..."); } }
客戶端測試類:
public class Client { public static void main(String[] args) { Context context = new Context(); context.setCurrentState(Context.OPEN); context.openMachine(); context.closeMachine(); } }
狀態(tài)模式的優(yōu)點有結(jié)構(gòu)清晰,避免了各種條件的判斷,省掉了swtich...case,if...else語句的使用,提升了代碼的可讀性。遵循了單一職責(zé)原則和開閉原則,每個狀態(tài)都是一個子類,增加狀態(tài)只需增加一個狀態(tài)子類,修改狀態(tài),修改對應(yīng)的子類就可以了。封裝性非常好,客戶端不需知道內(nèi)部狀態(tài)的轉(zhuǎn)換以及相應(yīng)的邏輯.其缺點就是狀態(tài)子類會太多,并且我們可以將狀態(tài)存儲到數(shù)據(jù)庫中,然后根據(jù)狀態(tài)執(zhí)行相應(yīng)的操作,這也是一種不錯的實現(xiàn)方式,具體如何使用看大家個人喜好了。
總結(jié)本章的行為型模式總結(jié)了策略模式、觀察者模式、責(zé)任鏈模式、模板方法模式和狀態(tài)模式,其實不僅于此,還有備忘錄模式和命令模式等,但因其使用場景有限,就不做一一探討了,留給讀者自己學(xué)習(xí)~.~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68293.html
摘要:分別為適配器模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。設(shè)計模式五適配器模式適配器模式將某個對象的接生成器和協(xié)程的實現(xiàn)在這篇文章中,作者針對那些比較難以理解的概念,以一個更為通俗的方式去講明白。。 PHP 源碼注解 PHP 的詳細(xì)源碼注解 PHP 字符串操作整理 一些有關(guān)字符串的常用操作。 Redis 常見七種使用場景 (PHP 實戰(zhàn)) 這篇文章主要介紹利用 R...
摘要:推文用設(shè)計模式解構(gòu)三國是一種什么體驗行為型設(shè)計模式一策略模式工廠模式優(yōu)化結(jié)構(gòu)狀態(tài)模式隨著狀態(tài)改變而改變行為。推文狀態(tài)機(jī)與狀態(tài)模式責(zé)任鏈模式多個對象依次處理請求前者指定后者。代理模式代理針對一個對象,為了增加控制等中介雙方都是多個,為了解耦。 策略模式 選擇使用封裝好的一系列算法,可相互替換。 類比:商店[Context]買完衣服買單[Stratege](現(xiàn)金[Concrete Stra...
摘要:在策略模式中,一個類的行為或其算法可以在運行時更改。這種類型的設(shè)計模式屬于行為型模式。而本次示例使用策略模式來實現(xiàn)這種數(shù)學(xué)運算。 在策略模式(Strategy Pattern)中,一個類的行為或其算法可以在運行時更改。這種類型的設(shè)計模式屬于行為型模式。其實現(xiàn)原理是定義一系列的算法,將他們一個個封裝起來,并且是他們可以互相替換,這樣避免了使用 if … else 語句所帶來的復(fù)雜度和維護(hù)...
摘要:設(shè)計模式的類別設(shè)計模式一共分為種類型,共種。屬于結(jié)構(gòu)型的設(shè)計模式適配器模式橋接模式裝飾模式組合模式外觀模式享元模式代理模式。問題描述了應(yīng)該在何時使用設(shè)計模式。解決方案描述了設(shè)計的組成成分,它們之間的相互關(guān)系及各自的職責(zé)和協(xié)作方式。 設(shè)計模式概述 1. 設(shè)計模式是什么 我們在平時編寫代碼的過程中,會遇到各種各樣的問題,細(xì)想一下很多問題的解決思路大致一樣的,這時候你就可以把解決問題的思路整...
閱讀 3028·2023-04-25 18:00
閱讀 2237·2021-11-23 10:07
閱讀 4081·2021-11-22 09:34
閱讀 1256·2021-10-08 10:05
閱讀 1579·2019-08-30 15:55
閱讀 3449·2019-08-30 11:21
閱讀 3352·2019-08-29 13:01
閱讀 1391·2019-08-26 18:26