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