<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          設(shè)計模式大冒險第五關(guān):狀態(tài)模式,if/else的“終結(jié)者”

          共 9851字,需瀏覽 20分鐘

           ·

          2021-02-23 00:22

          這一篇文章是關(guān)于設(shè)計模式大冒險系列的第五篇文章,這一系列的每一篇文章我都希望能夠通過通俗易懂的語言描述或者日常生活中的小例子來幫助大家理解好每一種設(shè)計模式。

          今天這篇文章來跟大家一起學(xué)習(xí)一下狀態(tài)模式。相信讀完這篇文章之后,你會收獲很多。在以后的開發(fā)中,如果遇到了類似的情況就知道如何更好地處理,能夠少用ifelse語句,以及switch語句,寫出更已讀,擴(kuò)展性更好,更易維護(hù)的程序。話不多說,我們開始今天的文章吧。

          開發(fā)過程中的一些場景

          我們在平時的開發(fā)過程中,經(jīng)常會遇到這樣一種情況:就是需要我們處理一個對象的不同狀態(tài)下的不同行為。比如最常見的就是訂單,訂單有很多種狀態(tài),每種狀態(tài)又對應(yīng)著不同的操作,有些操作是相同的,有些操作是不同的。再比如一個音樂播放器程序,在播放器緩沖音樂,播放,暫停,快進(jìn),快退,終止等的情況下又對應(yīng)著各種操作。有些操作在某些情況下是允許的,有些操作是不允許的。還有很多不同的場景,這里就不一一列舉了。

          那么面對上面說的這些情況我們應(yīng)該如何設(shè)計我們的程序,才能讓我們開發(fā)出來的程序更好維護(hù)與擴(kuò)展,也更方便別人閱讀呢?先別著急,我們一步一步來。遇到這種情況我們應(yīng)該首先把整個操作的狀態(tài)圖畫出來,只有狀態(tài)圖畫出來,我們才可以清晰的知道這個過程中會有哪些操作,都發(fā)生了哪些狀態(tài)的改變。只要我們做了這一步,然后按照狀態(tài)圖的邏輯去實現(xiàn)我們的程序;先不管代碼的質(zhì)量如何,至少可以保證我們的邏輯功能是滿足了需求的。

          生活小例子,我的吹風(fēng)機(jī)

          讓我們從生活中的一個小例子入手吧。最近我家里新買了一個吹風(fēng)機(jī),這個吹風(fēng)機(jī)有兩個按鈕。一個按鈕控制吹風(fēng)機(jī)的開關(guān),另一個按鈕可以在吹風(fēng)機(jī)打開的情況下切換吹風(fēng)的模式。吹風(fēng)機(jī)的模式有三種,分別是熱風(fēng),冷熱風(fēng)交替,和冷風(fēng)。并且吹風(fēng)機(jī)打開時默認(rèn)是熱風(fēng)模式。

          如果讓我們來編寫一個程序?qū)崿F(xiàn)上面所說的吹風(fēng)機(jī)的控制功能,我們應(yīng)該怎么實現(xiàn)呢?首先先別急著開始寫代碼,我們需要把吹風(fēng)機(jī)的狀態(tài)圖畫出來。如下圖所示:

          4c194ebb9d3d75fadc5645bd5a5f4421.webp吹風(fēng)機(jī)的狀態(tài)圖

          上面的狀態(tài)圖已經(jīng)把吹風(fēng)機(jī)的各種狀態(tài)都表示出來了,其中圓圈表示了吹風(fēng)機(jī)的狀態(tài),帶箭頭的線表示狀態(tài)轉(zhuǎn)換。從這個狀態(tài)圖我們可以很直觀的知道:吹風(fēng)機(jī)從關(guān)閉狀態(tài)到打開狀態(tài)默認(rèn)是熱風(fēng)模式,然后這三種模式可以按照順序進(jìn)行切換,然后在每一種模式下都可以直接關(guān)閉吹風(fēng)機(jī)

          一般的實現(xiàn)方式

          當(dāng)我們知道了整個吹風(fēng)機(jī)的狀態(tài)轉(zhuǎn)換之后,我們就可以開始寫代碼了。我們先按照最直觀的方式去實現(xiàn)我們的代碼。首先我們知道吹風(fēng)機(jī)有兩個按鈕,一個控制開關(guān),一個控制吹風(fēng)機(jī)的吹風(fēng)模式。那么我們的程序中需要有兩個變量來分別表示開關(guān)狀態(tài)吹風(fēng)機(jī)當(dāng)前所處的模式。這一部分的代碼如下所示:

          function?HairDryer()?{
          ???//?定義內(nèi)部狀態(tài)?0:關(guān)機(jī)狀態(tài)?1:開機(jī)狀態(tài)
          ???this.isOn?=?0;
          ???//?定義模式?0:熱風(fēng)?1:冷熱風(fēng)交替?2:冷風(fēng)
          ???this.mode?=?0;
          }

          接下來就要實現(xiàn)吹風(fēng)機(jī)的開關(guān)按鈕的功能了,這一部分比較簡單;我們只需要判斷當(dāng)前isOn變量,如果是打開狀態(tài)就將isOn設(shè)置為關(guān)閉狀態(tài),如果是關(guān)閉狀態(tài)就將isOn設(shè)置為打開狀態(tài)。需要注意的一點就是在吹風(fēng)機(jī)關(guān)閉的情況下需要將吹風(fēng)機(jī)的模式重置為熱風(fēng)模式。

          //?切換吹風(fēng)機(jī)的打開關(guān)閉狀態(tài)
          HairDryer.prototype.turnOnOrOff?=?function()?{
          ???let?{?isOn,?mode?}?=?this;
          ???if?(isOn?===?0)?{
          ??????//?打開吹風(fēng)機(jī)
          ??????isOn?=?1;
          ??????console.log('吹風(fēng)機(jī)的狀態(tài)變?yōu)椋篬打開狀態(tài)],模式是:[熱風(fēng)模式]');
          ???}?else?{
          ??????//?關(guān)閉吹風(fēng)機(jī)
          ??????isOn?=?0;
          ??????//?重置吹風(fēng)機(jī)的模式
          ????????mode?=?0;
          ??????console.log('吹風(fēng)機(jī)的狀態(tài)變?yōu)椋篬關(guān)閉狀態(tài)]');
          ???}
          ???this.isOn?=?isOn;
          ???this.mode?=?mode;
          };

          在接下來就是實現(xiàn)吹風(fēng)機(jī)的模式切換的功能了,代碼如下所示:

          //?切換吹風(fēng)機(jī)的模式
          HairDryer.prototype.switchMode?=?function()?{
          ???const?{?isOn?}?=?this;
          ???let?{?mode?}?=?this;
          ???//?切換模式的前提是:吹風(fēng)機(jī)是開啟狀態(tài)
          ???if?(isOn?===?1)?{
          ??????//?需要知道當(dāng)前模式
          ??????if?(mode?===?0)?{
          ?????????//?如果當(dāng)前是熱風(fēng)模式,切換之后就是冷熱風(fēng)交替模式
          ?????????mode?=?1;
          ?????????console.log('吹風(fēng)機(jī)的模式改變?yōu)椋篬冷熱風(fēng)交替模式]');
          ??????}?else?if?(mode?===?1)?{
          ?????????//?如果當(dāng)前是冷熱風(fēng)交替模式,切換之后就是冷風(fēng)模式
          ?????????mode?=?2;
          ?????????console.log('吹風(fēng)機(jī)的模式改變?yōu)椋篬冷風(fēng)模式]');
          ??????}?else?{
          ?????????//?如果當(dāng)前是冷風(fēng)模式,切換之后就是熱風(fēng)模式
          ?????????mode?=?0;
          ?????????console.log('吹風(fēng)機(jī)的模式改變?yōu)椋篬熱風(fēng)模式]');
          ??????}
          ???}?else?{
          ??????console.log('吹風(fēng)機(jī)在關(guān)閉的狀態(tài)下無法改變模式');
          ???}
          ???this.mode?=?mode;
          };

          這一部分的代碼也不算難,但是有一些細(xì)節(jié)需要注意。首先我們切換模式需要吹風(fēng)機(jī)是打開的狀態(tài),然后當(dāng)吹風(fēng)機(jī)是關(guān)閉的狀態(tài)的時候,我們不能夠切換模式。到這里為止,我們已經(jīng)把吹風(fēng)機(jī)的控制功能都實現(xiàn)了。接下來就要寫一些代碼來驗證一下我們上面的程序是否正確,測試的代碼如下所示:

          const?hairDryer?=?new?HairDryer();
          //?打開吹風(fēng)機(jī),切換吹風(fēng)機(jī)模式
          hairDryer.turnOnOrOff();
          hairDryer.switchMode();
          hairDryer.switchMode();
          hairDryer.switchMode();
          //?關(guān)閉吹風(fēng)機(jī),嘗試切換模式
          hairDryer.turnOnOrOff();
          hairDryer.switchMode();
          //?打開關(guān)閉吹風(fēng)機(jī)
          hairDryer.turnOnOrOff();
          hairDryer.turnOnOrOff();

          輸出的結(jié)果如下所示:

          吹風(fēng)機(jī)的狀態(tài)變?yōu)椋篬打開狀態(tài)],模式是:[熱風(fēng)模式]
          吹風(fēng)機(jī)的模式改變?yōu)椋篬冷熱風(fēng)交替模式]
          吹風(fēng)機(jī)的模式改變?yōu)椋篬冷風(fēng)模式]
          吹風(fēng)機(jī)的模式改變?yōu)椋篬熱風(fēng)模式]
          吹風(fēng)機(jī)的狀態(tài)變?yōu)椋篬關(guān)閉狀態(tài)]
          吹風(fēng)機(jī)在關(guān)閉的狀態(tài)下無法改變模式
          吹風(fēng)機(jī)的狀態(tài)變?yōu)椋篬打開狀態(tài)],模式是:[熱風(fēng)模式]
          吹風(fēng)機(jī)的狀態(tài)變?yōu)椋篬關(guān)閉狀態(tài)]

          從上面測試的結(jié)果我們可以知道,上面程序編寫的邏輯是沒有問題的,實現(xiàn)了我們想要的預(yù)期的功能。如果想看上面代碼的完整版本可以點擊這里瀏覽。

          但是你能從上面的代碼中看出什么問題嗎?作為一個優(yōu)秀的工程師,你肯定會發(fā)現(xiàn)上面的代碼使用了太多的if/else判斷,然后切換吹風(fēng)機(jī)模式的代碼都耦合在一起。這樣會導(dǎo)致一些問題,首先上面代碼的可讀性不是很好,如果沒有注釋的話,想要知道吹風(fēng)機(jī)模式的切換邏輯還是有點費力的。另一方面,上面代碼的可擴(kuò)展性也不是很好,如果我們想新增加一種模式的話,就需要修改if/else里面的判斷,很容易出錯。那么作為一個優(yōu)秀的工程師,我們該如何重構(gòu)上面的程序呢?

          狀態(tài)模式的介紹,以及使用狀態(tài)模式重構(gòu)之前的程序

          接下來我們就要進(jìn)入狀態(tài)模式的學(xué)習(xí)過程了,首先我們先不用管什么是狀態(tài)模式。我們先來再次看一下上面關(guān)于吹風(fēng)機(jī)的狀態(tài)圖,我們可以看到吹風(fēng)機(jī)在整個過程中有四種狀態(tài),分別是:關(guān)閉狀態(tài)熱風(fēng)模式狀態(tài),冷熱風(fēng)交替模式狀態(tài)冷風(fēng)模式狀態(tài)。然后這四種模式分別都有兩個操作,分別是切換模式切換吹風(fēng)機(jī)的打開和關(guān)閉狀態(tài)。(注:對于關(guān)閉狀態(tài),雖然無法切換模式,但是在這里我們也認(rèn)為這種狀態(tài)有這個操作,只是操作不會起作用。)

          那么我們是不是可以換一種思路去解決這個問題,我們可以把具體的操作封裝進(jìn)每一個狀態(tài)里面,然后由對應(yīng)的狀態(tài)去處理對應(yīng)的操作。我們只需要控制好狀態(tài)之間的切換就可以了。這樣做可以讓我們把相應(yīng)的操作委托給相應(yīng)的狀態(tài)去做,不需要再寫那么多的if/else去判斷狀態(tài),這樣做還可以讓我們把變化封裝進(jìn)對應(yīng)的狀態(tài)中去。如果需要添加新的狀態(tài),我們對原來的代碼的改動也會很小。

          狀態(tài)模式的簡單介紹

          那么到這里我們來介紹一下狀態(tài)模式吧,狀態(tài)模式指的是:能夠在對象的內(nèi)部狀態(tài)改變的時候改變對象的行為狀態(tài)模式常常用來對一個對象在不同狀態(tài)下同樣操作時產(chǎn)生的不同行為進(jìn)行封裝,從而達(dá)到可以讓對象在運行時改變其行為的能力。就像我們上面說的吹風(fēng)機(jī),在熱風(fēng)模式下,按下模式切換按鈕可以切換到冷熱風(fēng)交替模式;但是如果當(dāng)前狀態(tài)是冷熱風(fēng)交替模式,那么按下模式切換按鈕,就切換到了冷風(fēng)模式了。更詳細(xì)的解釋可以參考State pattern

          我們再來看一下狀態(tài)模式的UML圖,如下所示:

          23c0d83b3d12127a03dbc0faed429464.webp狀態(tài)模式的UML圖

          可以看到,對于狀態(tài)模式來說,有一個Context(上下文),一個抽象的State類,這個抽象類定義好了每一個具體的類需要實現(xiàn)的方法。對于每一個具體的類來說,它實現(xiàn)了抽象類State定義好的方法,然后Context在需要進(jìn)行操作的時候,只需要請求對應(yīng)具體狀態(tài)類實例的對應(yīng)方法就可以了。

          使用狀態(tài)模式來重構(gòu)之前的程序

          接下來我們來用狀態(tài)模式來重構(gòu)我們的程序,首先是Context,對應(yīng)的代碼如下所示:

          //?狀態(tài)模式
          //?吹風(fēng)機(jī)
          class?HairDryer?{
          ???//?吹風(fēng)機(jī)的狀態(tài)
          ???state;
          ???//?關(guān)機(jī)狀態(tài)
          ???offState;
          ???//?開機(jī)熱風(fēng)狀態(tài)
          ???hotAirState;
          ???//?開機(jī)冷熱風(fēng)交替狀態(tài)
          ???alternateHotAndColdAirState;
          ???//?開機(jī)冷風(fēng)狀態(tài)
          ???coldAirState;

          ???//?構(gòu)造函數(shù)
          ???constructor(state)?{
          ??????this.offState?=?new?OffState(this);
          ??????this.hotAirState?=?new?HotAirState(this);
          ??????this.alternateHotAndColdAirState?=?new?AlternateHotAndColdAirState(
          ?????????this
          ??????);
          ??????this.coldAirState?=?new?ColdAirState(this);
          ??????if?(state)?{
          ?????????this.state?=?state;
          ??????}?else?{
          ?????????//?默認(rèn)是關(guān)機(jī)狀態(tài)
          ?????????this.state?=?this.offState;
          ??????}
          ???}

          ???//?設(shè)置吹風(fēng)機(jī)的狀態(tài)
          ???setState(state)?{
          ??????this.state?=?state;
          ???}

          ???//?開關(guān)機(jī)按鈕
          ???turnOnOrOff()?{
          ??????this.state.turnOnOrOff();
          ???}
          ???//?切換模式按鈕
          ???switchMode()?{
          ??????this.state.switchMode();
          ???}

          ???//?獲取吹風(fēng)機(jī)的關(guān)機(jī)狀態(tài)
          ???getOffState()?{
          ??????return?this.offState;
          ???}
          ???//?獲取吹風(fēng)機(jī)的開機(jī)熱風(fēng)狀態(tài)
          ???getHotAirState()?{
          ??????return?this.hotAirState;
          ???}
          ???//?獲取吹風(fēng)機(jī)的開機(jī)冷熱風(fēng)交替狀態(tài)
          ???getAlternateHotAndColdAirState()?{
          ??????return?this.alternateHotAndColdAirState;
          ???}
          ???//?獲取吹風(fēng)機(jī)的開機(jī)冷風(fēng)狀態(tài)
          ???getColdAirState()?{
          ??????return?this.coldAirState;
          ???}
          }

          我來解釋一下上面的代碼,首先我們使用HairDryer來表示Context,然后HairDryer類的實例屬性有state,這屬性就是表示了吹風(fēng)機(jī)當(dāng)前所處的狀態(tài)。其余的四個屬性分別表示吹風(fēng)機(jī)對應(yīng)的四個狀態(tài)實例。

          吹風(fēng)機(jī)有setState可以設(shè)置吹風(fēng)機(jī)的狀態(tài),然后getOffStategetHotAirState,getAlternateHotAndColdAirState,getColdAirState分別用來獲取吹風(fēng)機(jī)的對應(yīng)狀態(tài)實例。你可能會說為什么要在HairDryer類里面獲取相應(yīng)的狀態(tài)實例呢?別著急,下面會解釋為什么。

          然后turnOnOrOff方法表示打開或者關(guān)閉吹風(fēng)機(jī),switchMode用來表示切換吹風(fēng)機(jī)的模式。還有constructor,我們默認(rèn)如果沒有傳遞狀態(tài)實例的話,默認(rèn)是熱風(fēng)模式狀態(tài)。

          然后是我們的抽象類State,因為我們的實現(xiàn)使用的語言是JavaScriptJavaScript暫時還不支持抽象類,所以用一般的類來代替。這個對我們實現(xiàn)狀態(tài)模式?jīng)]有太大的影響。具體的代碼如下:

          //?抽象的狀態(tài)
          class?State?{
          ???//?開關(guān)機(jī)按鈕
          ???turnOnOrOff()?{
          ??????console.log('---按下吹風(fēng)機(jī)?[開關(guān)機(jī)]?按鈕---');
          ???}
          ???//?切換模式按鈕
          ???switchMode()?{
          ??????console.log('---按下吹風(fēng)機(jī)?[模式切換]?按鈕---');
          ???}
          }

          State類主要是用來定義好具體的狀態(tài)類應(yīng)該實現(xiàn)的方法,對于我們這個吹風(fēng)機(jī)的例子來說就是turnOnOrOffswitchMode。它們分別對應(yīng),按下吹風(fēng)機(jī)開關(guān)機(jī)按鈕的處理和按下吹風(fēng)機(jī)的模式切換按鈕的處理。

          接下來就是具體的狀態(tài)類的實現(xiàn)了,代碼如下所示:

          //?吹風(fēng)機(jī)的關(guān)機(jī)狀態(tài)
          class?OffState?extends?State?{
          ???//?吹風(fēng)機(jī)對象的引用
          ???hairDryer;
          ???constructor(hairDryer)?{
          ??????super();
          ??????this.hairDryer?=?hairDryer;
          ???}
          ???//?開關(guān)機(jī)按鈕
          ???turnOnOrOff()?{
          ??????super.turnOnOrOff();
          ??????this.hairDryer.setState(this.hairDryer.getHotAirState());
          ??????console.log('狀態(tài)切換:?關(guān)閉狀態(tài)?=>?開機(jī)熱風(fēng)狀態(tài)');
          ???}
          ???//?切換模式按鈕
          ???switchMode()?{
          ??????console.log('===吹風(fēng)機(jī)在關(guān)閉的狀態(tài)下無法切換模式===');
          ???}
          }

          //?吹風(fēng)機(jī)的開機(jī)熱風(fēng)狀態(tài)
          class?HotAirState?extends?State?{
          ???//?吹風(fēng)機(jī)對象的引用
          ???hairDryer;
          ???constructor(hairDryer)?{
          ??????super();
          ??????this.hairDryer?=?hairDryer;
          ???}
          ???//?開關(guān)機(jī)按鈕
          ???turnOnOrOff()?{
          ??????super.turnOnOrOff();
          ??????this.hairDryer.setState(this.hairDryer.getOffState());
          ??????console.log('狀態(tài)切換:?開機(jī)熱風(fēng)狀態(tài)?=>?關(guān)閉狀態(tài)');
          ???}
          ???//?切換模式按鈕
          ???switchMode()?{
          ??????super.switchMode();
          ??????this.hairDryer.setState(
          ?????????this.hairDryer.getAlternateHotAndColdAirState()
          ??????);
          ??????console.log('狀態(tài)切換:?開機(jī)熱風(fēng)狀態(tài)?=>?開機(jī)冷熱風(fēng)交替狀態(tài)');
          ???}
          }

          //?吹風(fēng)機(jī)的開機(jī)冷熱風(fēng)交替狀態(tài)
          class?AlternateHotAndColdAirState?extends?State?{
          ???//?吹風(fēng)機(jī)對象的引用
          ???hairDryer;
          ???constructor(hairDryer)?{
          ??????super();
          ??????this.hairDryer?=?hairDryer;
          ???}
          ???//?開關(guān)機(jī)按鈕
          ???turnOnOrOff()?{
          ??????super.turnOnOrOff();
          ??????this.hairDryer.setState(this.hairDryer.getOffState());
          ??????console.log('狀態(tài)切換:?開機(jī)冷熱風(fēng)交替狀態(tài)?=>?關(guān)閉狀態(tài)');
          ???}
          ???//?切換模式按鈕
          ???switchMode()?{
          ??????super.switchMode();
          ??????this.hairDryer.setState(this.hairDryer.getColdAirState());
          ??????console.log('狀態(tài)切換:?開機(jī)冷熱風(fēng)交替狀態(tài)?=>?開機(jī)冷風(fēng)狀態(tài)');
          ???}
          }

          //?吹風(fēng)機(jī)的開機(jī)冷風(fēng)狀態(tài)
          class?ColdAirState?extends?State?{
          ???//?吹風(fēng)機(jī)對象的引用
          ???hairDryer;
          ???constructor(hairDryer)?{
          ??????super();
          ??????this.hairDryer?=?hairDryer;
          ???}
          ???//?開關(guān)機(jī)按鈕
          ???turnOnOrOff()?{
          ??????super.turnOnOrOff();
          ??????this.hairDryer.setState(this.hairDryer.getOffState());
          ??????console.log('狀態(tài)切換:?開機(jī)冷風(fēng)狀態(tài)?=>?關(guān)閉狀態(tài)');
          ???}
          ???//?切換模式按鈕
          ???switchMode()?{
          ??????super.switchMode();
          ??????this.hairDryer.setState(this.hairDryer.getHotAirState());
          ??????console.log('狀態(tài)切換:?開機(jī)冷風(fēng)狀態(tài)?=>?開機(jī)熱風(fēng)狀態(tài)');
          ???}
          }

          由上面的代碼我們可以看到,對于每一個具體的類來說,都有一個屬性hairDryer,這個屬性用來保存吹風(fēng)機(jī)實例的索引。然后就是對應(yīng)turnOnOrOffswitchMode方法的實現(xiàn)。我們可以看到在具體的類中我們設(shè)置hairDryer的狀態(tài)是通過hairDryer實例的setState方法,然后獲取狀態(tài)是通過hairDryer對應(yīng)的獲取狀態(tài)的方法。比如:this.hairDryer.getHotAirState()就是獲取吹風(fēng)機(jī)的熱風(fēng)模式狀態(tài)。

          在這里我們可以說一下為什么要在HairDryer類里面獲取相應(yīng)的狀態(tài)實例:因為這樣不同的狀態(tài)類之間相當(dāng)于解耦了,它們不需要在各自的類中依賴對應(yīng)的狀態(tài),直接從hairDryer實例上獲取對應(yīng)的狀態(tài)實例就可以了。減少了類之間的依賴,使我們代碼的可維護(hù)性變的更好了

          接下來就是需要測試一下我們上面通過狀態(tài)模式重構(gòu)后的代碼有沒有實現(xiàn)我們想要的功能,測試的代碼如下:

          const?hairDryer?=?new?HairDryer();
          //?打開吹風(fēng)機(jī)
          hairDryer.turnOnOrOff();
          //?切換模式
          hairDryer.switchMode();
          //?切換模式
          hairDryer.switchMode();
          //?切換模式
          hairDryer.switchMode();
          //?關(guān)閉吹風(fēng)機(jī)
          hairDryer.turnOnOrOff();
          //?吹風(fēng)機(jī)在關(guān)閉的狀態(tài)下無法切換模式
          hairDryer.switchMode();

          輸出的結(jié)果如下所示:

          ---按下吹風(fēng)機(jī)?[開關(guān)機(jī)]?按鈕---
          狀態(tài)切換:?關(guān)閉狀態(tài)?=>?開機(jī)熱風(fēng)狀態(tài)
          ---按下吹風(fēng)機(jī)?[模式切換]?按鈕---
          狀態(tài)切換:?開機(jī)熱風(fēng)狀態(tài)?=>?開機(jī)冷熱風(fēng)交替狀態(tài)
          ---按下吹風(fēng)機(jī)?[模式切換]?按鈕---
          狀態(tài)切換:?開機(jī)冷熱風(fēng)交替狀態(tài)?=>?開機(jī)冷風(fēng)狀態(tài)
          ---按下吹風(fēng)機(jī)?[模式切換]?按鈕---
          狀態(tài)切換:?開機(jī)冷風(fēng)狀態(tài)?=>?開機(jī)熱風(fēng)狀態(tài)
          ---按下吹風(fēng)機(jī)?[開關(guān)機(jī)]?按鈕---
          狀態(tài)切換:?開機(jī)熱風(fēng)狀態(tài)?=>?關(guān)閉狀態(tài)
          ===吹風(fēng)機(jī)在關(guān)閉的狀態(tài)下無法切換模式===

          根據(jù)上面的測試結(jié)果可以知道,我們重構(gòu)之后的代碼也完美地實現(xiàn)了我們想要的功能。使用狀態(tài)模式重構(gòu)后的完整版本可以點擊這里瀏覽。那么接下來我們就來分析一下,使用狀態(tài)模式與第一種不使用狀態(tài)模式相比有哪些優(yōu)勢和劣勢。

          使用狀態(tài)模式的優(yōu)勢有以下幾個方面:

          • 將應(yīng)用的代碼解耦,利于閱讀和維護(hù)。我們可以看到,在第一種方案中,我們使用了大量的if/else來進(jìn)行邏輯的判斷,將各種狀態(tài)和邏輯放在一起進(jìn)行處理。在我們應(yīng)用相關(guān)對象的狀態(tài)比較少的情況下可能不會有太大的問題,但是一旦對象的狀態(tài)變得多了起來,這種耦合比較深的代碼維護(hù)起來就很困難,很折磨人。

          • 將變化封裝進(jìn)具體的狀態(tài)對象中,相當(dāng)于將變化局部化,并且進(jìn)行了封裝。利于以后的維護(hù)與拓展。使用狀態(tài)模式之后,我們把相關(guān)的操作都封裝進(jìn)對應(yīng)的狀態(tài)中,如果想修改或者添加新的狀態(tài),也是很方便的。對代碼的修改也比較少,擴(kuò)展性比較好。

          • 通過組合和委托,讓對象在運行的時候可以通過改變狀態(tài)來改變自己的行為。我們只需要將對象的狀態(tài)圖畫出來,專注于對象的狀態(tài)改變,以及每個狀態(tài)有哪些行為。這讓我們的開發(fā)變得簡單一些,也不容易出錯,能夠保證我們寫出來的代碼質(zhì)量是不錯的。

          使用狀態(tài)模式的劣勢:

          • 當(dāng)然使用狀態(tài)模式也有一點劣勢,那就是增加了代碼中類的數(shù)量,也就是增加了代碼量。但是在絕大多數(shù)情況下來說,這個算不上什么太大的問題。除非你開發(fā)的應(yīng)用對代碼量有著比較嚴(yán)格的要求。

          狀態(tài)模式的總結(jié)

          通過上面對狀態(tài)模式的講解,以及吹風(fēng)機(jī)小例子的實踐,相信大家對狀態(tài)模式都有了很深入的理解。在平時的開發(fā)工作中,如果一個對象有很多種狀態(tài),并且這個對象在不同狀態(tài)下的行為也不一樣,那么我們就可以使用狀態(tài)模式來解決這個問題。使用狀態(tài)模式可以讓我們的代碼條理清楚,容易閱讀;也方便維護(hù)和擴(kuò)展

          為了驗證你的確已經(jīng)掌握了狀態(tài)模式,這里給大家出個小題目。還是以上面的吹風(fēng)機(jī)為例子,如果現(xiàn)在吹風(fēng)機(jī)新增加了一個按鈕,用來切換風(fēng)速強(qiáng)度的大小。默認(rèn)風(fēng)速的強(qiáng)度是弱風(fēng),按下按鈕變?yōu)閺?qiáng)風(fēng)。現(xiàn)在你能修改上面的代碼,然后實現(xiàn)這個功能嗎,趕快動手試試吧~

          文章到這里就結(jié)束了,如果大家有什么問題和疑問歡迎大家在文章下面留言,或者在dreamapplehappy/blog提出來。也歡迎大家關(guān)注我的公眾號關(guān)山不難越,獲取更多關(guān)于設(shè)計模式講解的內(nèi)容。

          下面是這一系列的其它的文章,也歡迎大家閱讀,希望大家都能夠掌握好這些設(shè)計模式的使用場景和解決的方法。如果這篇文章對你有所幫助,那就點個贊,分享一下吧~

          參考鏈接:

          • State pattern,文中狀態(tài)模式的UML圖片也來自這里。
          • Take Control of your App with the JavaScript State Pattern
          • The State Design Pattern vs State Machine


          瀏覽 36
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产,黄片,免费,在线看 | 欧美黄片99 | 久操久热 | 欧美一交一乱一交一色一色情 | 操逼无码视频 |