摘要:定義狀態(tài)模式,當(dāng)一個對象的內(nèi)部狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類??偨Y(jié)狀態(tài)模式和和策略模式有點相像,狀態(tài)模式的狀態(tài)轉(zhuǎn)移是內(nèi)部控制的,而策略模式是由客戶端控制采用不同的策略。
定義
狀態(tài)模式(State),當(dāng)一個對象的內(nèi)部狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類。類圖
Context:環(huán)境,上下文,其實就是狀態(tài)管理者,隱藏了狀態(tài)之間轉(zhuǎn)換的細(xì)節(jié),是客戶端與各個狀態(tài)的中間人。request()方法是客戶端調(diào)用的,
State:抽象狀態(tài),定義了狀態(tài)的處理抽象方法handle(),各個具體狀態(tài)需要實現(xiàn)它。
ConcreteState:具體狀態(tài),實現(xiàn)了狀態(tài)的公共方法,且包含了狀態(tài)轉(zhuǎn)換的判斷。
經(jīng)典源碼狀態(tài)管理者
public class Context { //持有一個State類型的對象實例 private State state; public void setState(State state) { this.state = state; } /** * 客戶端調(diào)用 */ public void request(String sampleParameter) { //轉(zhuǎn)調(diào)state來處理 state.handle(sampleParameter); } }
抽象狀態(tài)
public interface State { /** * 狀態(tài)對應(yīng)的處理 */ public void handle(String sampleParameter); }
具體狀態(tài)A
public class ConcreteStateA implements State { @Override public void handle(String sampleParameter) { System.out.println("ConcreteStateA handle :" + sampleParameter); } }
具體狀態(tài)B
public class ConcreteStateB implements State { @Override public void handle(String sampleParameter) { System.out.println("ConcreteStateB handle :" + sampleParameter); } }
客戶端調(diào)用方
public class Client { public static void main(String[] args){ //創(chuàng)建狀態(tài) State state = new ConcreteStateB(); //創(chuàng)建環(huán)境 Context context = new Context(); //將狀態(tài)設(shè)置到環(huán)境中 context.setState(state); //請求 context.request("test"); } }實際案例 背景
小A正在召喚師峽谷廝殺,他玩的是卡特,買了一本殺人書。隨著游戲時間的進(jìn)行,小A殺的人越來越多,且自己都沒死過,游戲中不斷傳來“XXX暴走了”、“XXX主宰了比賽”、“XXX接近神了”。最終小A以12殺0死的完美戰(zhàn)績結(jié)束了比賽,腦海中剛才的捷報聲還在不停環(huán)繞在他的耳邊,他就想這不就是狀態(tài)模式,隨后打開IDE開始復(fù)現(xiàn)剛才的過程。
結(jié)構(gòu)環(huán)境類
package com.jo.state; /** * @author Jo * @date 2018/1/17 */ public class LolContext { /** * 當(dāng)前殺人狀態(tài) */ private KillState killState; /** * 當(dāng)前殺人數(shù) */ private Integer killNum = 0; public LolContext() { killState = new Normal(); } public Integer getKillNum() { return killNum; } public LolContext setKillState(KillState killState) { this.killState = killState; return this; } /** * 殺人方法, */ public void kill(){ killNum += 1; killState.kill(this); System.out.println("當(dāng)前擊殺數(shù)" + killNum); System.out.println(); } }
抽象殺人狀態(tài)
public interface KillState { /** * 抽象殺人方法 * @param lolContext */ void kill(LolContext lolContext); }
普通擊殺
public class Normal implements KillState { @Override public void kill(LolContext lolContext) { System.out.println("你殺了一個人"); //殺了2個人的時候轉(zhuǎn)換狀態(tài) if (lolContext.getKillNum() > 1){ lolContext.setKillState(new KillingSpring()); } } }
大殺特殺
public class KillingSpring implements KillState { @Override public void kill(LolContext lolContext) { System.out.println("你正在大殺特殺"); lolContext.setKillState(new Rampage()); } }
接近暴走
public class Rampage implements KillState { @Override public void kill(LolContext lolContext) { System.out.println("你已經(jīng)接近暴走了"); lolContext.setKillState(new Unstoppable()); } }
無人可擋
public class Unstoppable implements KillState { @Override public void kill(LolContext lolContext) { System.out.println("你已經(jīng)無人可擋了"); lolContext.setKillState(new Dominating()); } }
、
、
、
、
超神
public class Legendary implements KillState { @Override public void kill(LolContext lolContext) { System.out.println("你已經(jīng)超神了"); } }
客戶端調(diào)用
public class Client { public static void main(String[] args) { LolContext lolContext = new LolContext(); for (int i = 0; i < 13; i++) { lolContext.kill(); } } }
運行結(jié)果
客戶端只負(fù)責(zé)調(diào)用LolContext的kill方法,其余一概不知,內(nèi)部便會隨著殺人數(shù)的增長打印不同的通知。而LolContext中也沒有復(fù)雜,一大串的if else switch case,狀態(tài)的轉(zhuǎn)移在各自的具體狀態(tài)中,如果需要修改部分邏輯只需要改對應(yīng)的狀態(tài),而不需要改原本在一起的if else,大大減少了隱患的發(fā)生率,從而不會發(fā)生牽一發(fā)而動全身的結(jié)果。
適用場景狀態(tài)模式的優(yōu)點是解除了程序的耦合度,采用子類的方式去除了煩瑣容易出錯的if else,但反而帶來的是類的數(shù)據(jù)增多。如果你要實現(xiàn)的功能狀態(tài)不多,且功能簡單,那不推薦使用狀態(tài)模式,不然會徒增程序的復(fù)雜性。且要執(zhí)行的動作有一定的復(fù)雜度,此例的kill方法是最簡單的實現(xiàn),實際應(yīng)用中復(fù)雜度是遠(yuǎn)遠(yuǎn)大于它的。你可以想象在狀態(tài)多,且復(fù)雜的動作中不使用狀態(tài)模式會事怎樣,if else多的眼花繚亂,上一個if和下一個else if相差幾百行代碼,想必這樣的代碼誰都不愿意碰,萬一改壞了就要背鍋了。
總結(jié)狀態(tài)模式和和策略模式有點相像,狀態(tài)模式的狀態(tài)轉(zhuǎn)移是內(nèi)部控制的,而策略模式是由客戶端控制采用不同的策略。因此在目的和實現(xiàn)還是有很大的差別的。有些場景“狀態(tài)”不是那么明顯,需要轉(zhuǎn)換成狀態(tài)模式就考察使用者的功底和對業(yè)務(wù)的理解程度了,望大家都能get更多知識點,能力越來越強,個個都是架構(gòu)師。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/68263.html
摘要:簡介狀態(tài)模式允許一個對象在其內(nèi)部狀態(tài)改變的時候改變它的行為,對象看起來似乎修改了它的類。狀態(tài)通常為一個或多個枚舉常量的表示。簡而言之,當(dāng)遇到很多同級或者的時候,可以使用狀態(tài)模式來進(jìn)行簡化。 1. 簡介 狀態(tài)模式(State)允許一個對象在其內(nèi)部狀態(tài)改變的時候改變它的行為,對象看起來似乎修改了它的類。其實就是用一個對象或者數(shù)組記錄一組狀態(tài),每個狀態(tài)對應(yīng)一個實現(xiàn),實現(xiàn)的時候根據(jù)狀態(tài)挨個去運...
摘要:在狀態(tài)模式中,我們創(chuàng)建表示各種狀態(tài)的對象和一個行為隨著狀態(tài)對象改變而改變的對象。缺點狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個數(shù)。狀態(tài)模式是指允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為,對象看起來似乎修改了它的類。 狀態(tài)模式 在狀態(tài)模式(State Pattern)中,類的行為是基于它的狀態(tài)改變的。這種類型的設(shè)計模式屬于行為型模式。在狀態(tài)模式中,我們創(chuàng)建表示各種狀態(tài)的對象和一個行為隨著狀...
摘要:備忘錄模式常常與命令模式和迭代子模式一同使用。自述歷史所謂自述歷史模式實際上就是備忘錄模式的一個變種。在備忘錄模式中,發(fā)起人角色負(fù)責(zé)人角色和備忘錄角色都是獨立的角色。 備忘錄模式(Memento Pattern)屬于行為型模式的一種,在不破壞封裝特性的前提下,捕獲一個對象的內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài)。這樣就可以將該對象恢復(fù)到原先保存的狀態(tài)。 概述 備忘錄模式又叫做快照模式(...
摘要:為了實現(xiàn)這個正義偷笑又合理的訴求,你得先學(xué)會今天要介紹的設(shè)計模式,因為你們公司的這個流程可能就是用今天這個模式設(shè)計的。狀態(tài)模式對開閉原則的支持并不太好,新增狀態(tài)時,不僅得增加狀態(tài)類,還得修改原來已經(jīng)有的狀態(tài),讓之前的狀態(tài)切換到新增的狀態(tài)。一、定義你是否經(jīng)常請(偷)假(懶)?是不是對公司萬惡的請假申請流程深惡痛絕。有沒有想過偷偷改造這個萬惡的系統(tǒng),從 申請->項目經(jīng)理審批->部門審批->老板審...
摘要:要注意這里的一個狀態(tài)行為因為這個詞是狀態(tài)模式中最重要的個概念??紤]到這點,聰明的在中推出了狀態(tài)機這個偽函數(shù),能夠幫助我們快速實現(xiàn)狀態(tài)化。這里就引入了狀態(tài)機這個概念,以及和他對應(yīng)的狀態(tài)表。 ?首先聲明一點,這個模式是我目前見過最好用(本人觀點),但是也是最難理解的一個(本人觀點)。 所以大家需要做好心理準(zhǔn)備,如果,對這個模式?jīng)]有特別強烈的需求,比如: 我有一個Button,我按次數(shù)點擊它...
閱讀 2407·2021-10-09 09:41
閱讀 1806·2019-08-30 15:53
閱讀 1057·2019-08-30 15:52
閱讀 3523·2019-08-30 11:26
閱讀 835·2019-08-29 16:09
閱讀 3506·2019-08-29 13:25
閱讀 2328·2019-08-26 16:45
閱讀 1995·2019-08-26 11:51