<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>

          「補(bǔ)課」進(jìn)行時:設(shè)計模式(19)——狀態(tài)模式

          共 7835字,需瀏覽 16分鐘

           ·

          2020-12-17 17:56

          1. 前文匯總

          「補(bǔ)課」進(jìn)行時:設(shè)計模式系列

          2. LOL 中的狀態(tài)

          感覺我天天在用 LOL 舉例子,沒辦法,都已經(jīng) S11 了,而我依然在玩這個游戲。

          LOL 中的英雄有很多狀態(tài),有正常狀態(tài),有吃了偉哥一樣的加速狀態(tài),有被對方套了虛弱的虛弱狀態(tài),還有被對方控制的眩暈狀態(tài)。

          下面來看下,在 LOL 中,初始的英雄狀態(tài):

          public?class?Hero?{
          ????//正常狀態(tài)
          ????public?static?final?int?COMMON?=?1;
          ????//加速狀態(tài)
          ????public?static?final?int?SPEED_UP?=?2;
          ????//減速狀態(tài)
          ????public?static?final?int?SPEED_DOWN?=?3;
          ????//眩暈狀態(tài)
          ????public?static?final?int?SWIM?=?4;
          ????//默認(rèn)是正常狀態(tài)
          ????private?int?state?=?COMMON;
          ????//跑動線程
          ????private?Thread?runThread;
          ????//設(shè)置狀態(tài)
          ????public?void?setState(int?state)?{
          ????????this.state?=?state;
          ????}
          ????//停止跑動
          ????public?void?stopRun()?{
          ????????if?(isRunning())?runThread.interrupt();
          ????????System.out.println("--------------停止跑動---------------");
          ????}
          ????//開始跑動
          ????public?void?startRun()?{
          ????????if?(isRunning())?{
          ????????????return;
          ????????}
          ????????final?Hero?hero?=?this;
          ????????runThread?=?new?Thread(new?Runnable()?{
          ????????????public?void?run()?{
          ????????????????while?(!runThread.isInterrupted())?{
          ????????????????????try?{
          ????????????????????????hero.run();
          ????????????????????}?catch?(InterruptedException?e)?{
          ????????????????????????break;
          ????????????????????}
          ????????????????}
          ????????????}
          ????????});
          ????????System.out.println("--------------開始跑動---------------");
          ????????runThread.start();
          ????}
          ????private?boolean?isRunning(){
          ????????return?runThread?!=?null?&&?!runThread.isInterrupted();
          ????}
          ????//英雄類開始奔跑
          ????private?void?run()?throws?InterruptedException{
          ????????if?(state?==?SPEED_UP)?{
          ????????????System.out.println("--------------加速跑動---------------");
          ????????????Thread.sleep(2000);//假設(shè)加速持續(xù)2秒
          ????????????state?=?COMMON;
          ????????????System.out.println("------加速狀態(tài)結(jié)束,變?yōu)檎顟B(tài)------");
          ????????}else?if?(state?==?SPEED_DOWN)?{
          ????????????System.out.println("--------------減速跑動---------------");
          ????????????Thread.sleep(2000);//假設(shè)減速持續(xù)2秒
          ????????????state?=?COMMON;
          ????????????System.out.println("------減速狀態(tài)結(jié)束,變?yōu)檎顟B(tài)------");
          ????????}else?if?(state?==?SWIM)?{
          ????????????System.out.println("--------------不能跑動---------------");
          ????????????Thread.sleep(1000);//假設(shè)眩暈持續(xù)2秒
          ????????????state?=?COMMON;
          ????????????System.out.println("------眩暈狀態(tài)結(jié)束,變?yōu)檎顟B(tài)------");
          ????????}else?{
          ????????????//正常跑動則不打印內(nèi)容
          ????????}
          ????}
          }

          場景類:

          public?class?Client?{
          ????public?static?void?main(String[]?args)?throws?InterruptedException?{
          ????????Hero?hero?=?new?Hero();
          ????????hero.startRun();
          ????????hero.setState(Hero.SPEED_UP);
          ????????Thread.sleep(2000);
          ????????hero.setState(Hero.SPEED_DOWN);
          ????????Thread.sleep(2000);
          ????????hero.setState(Hero.SWIM);
          ????????Thread.sleep(2000);
          ????????hero.stopRun();
          ????}
          }

          可以看到,我們的英雄在跑動過程中隨著狀態(tài)的改變,我們的英雄會以不同的狀態(tài)進(jìn)行跑動。

          但是問題也隨之而來,我們的英雄類當(dāng)中有明顯的 if else 結(jié)構(gòu),這并不是我們希望看到的,接下來,我們看下狀態(tài)模式。

          3. 狀態(tài)模式

          3.1 定義

          狀態(tài)模式的定義如下:

          Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(當(dāng)一個對象內(nèi)在狀態(tài)改變時允許其改變行為, 這個對象看起來像改變了其類。)

          3.2 通用類圖

          • State 抽象狀態(tài)角色:接口或抽象類, 負(fù)責(zé)對象狀態(tài)定義, 并且封裝環(huán)境角色以實(shí)現(xiàn)狀態(tài)切換。
          • ConcreteState 具體狀態(tài)角色:每一個具體狀態(tài)必須完成兩個職責(zé):本狀態(tài)的行為管理以及趨向狀態(tài)處理, 通俗地說,就是本狀態(tài)下要做的事情, 以及本狀態(tài)如何過渡到其他狀態(tài)。
          • Context 環(huán)境角色:定義客戶端需要的接口, 并且負(fù)責(zé)具體狀態(tài)的切換。

          狀態(tài)模式從類圖上看比較簡單,實(shí)際上還是比較復(fù)雜的,它提供了一種對物質(zhì)運(yùn)動的另一個觀察視角, 通過狀態(tài)變更促使行為的變化。

          類似水的狀態(tài)變更一樣, 一碗水的初始狀態(tài)是液態(tài), 通過加熱轉(zhuǎn)變?yōu)?、氣態(tài), 狀態(tài)的改變同時也引起體積的擴(kuò)大, 然后就產(chǎn)生了一個新的行為:鳴笛或頂起壺蓋,瓦特就是這么發(fā)明蒸汽機(jī)的。

          3.3 通用代碼:

          抽象環(huán)境角色:

          public?abstract?class?State?{
          ????//?定義一個環(huán)境角色,提供子類訪問
          ????protected?Context?context;
          ????//?設(shè)置環(huán)境資源
          ????public?void?setContext(Context?context)?{
          ????????this.context?=?context;
          ????}
          ????//?行為1
          ????abstract?void?handle1();
          ????//?行為2
          ????abstract?void?handle2();
          }

          具體環(huán)境角色:

          public?class?ConcreteState1?extends?State?{
          ????@Override
          ????void?handle1()?{
          ????????//本狀態(tài)下必須處理的邏輯
          ????}

          ????@Override
          ????void?handle2()?{
          ????????//設(shè)置當(dāng)前狀態(tài)為stat2
          ????????super.context.setCurrentState(Context.STATE2);
          ????????//過渡到state2狀態(tài),?由Context實(shí)現(xiàn)
          ????????super.context.handle2();
          ????}
          }

          public?class?ConcreteState2?extends?State?{
          ????@Override
          ????void?handle1()?{
          ????????//設(shè)置當(dāng)前狀態(tài)為stat2
          ????????super.context.setCurrentState(Context.STATE1);
          ????????//過渡到state2狀態(tài),?由Context實(shí)現(xiàn)
          ????????super.context.handle1();
          ????}

          ????@Override
          ????void?handle2()?{
          ????????//?本狀態(tài)下必須處理的邏輯
          ????}
          }

          具體環(huán)境角色:

          public?class?Context?{
          ????final?static?State?STATE1?=?new?ConcreteState1();
          ????final?static?State?STATE2?=?new?ConcreteState2();

          ????private?State?concreteState;

          ????public?State?getCurrentState()?{
          ????????return?concreteState;
          ????}
          ????//設(shè)置當(dāng)前狀態(tài)
          ????public?void?setCurrentState(State?currentState)?{
          ????????this.concreteState?=?currentState;
          ????????//切換狀態(tài)
          ????????this.concreteState.setContext(this);
          ????}
          ????public?void?handle1(){
          ????????this.concreteState.handle1();
          ????}
          ????public?void?handle2(){
          ????????this.concreteState.handle2();
          ????}
          }

          環(huán)境角色有兩個不成文的約束:

          • 把狀態(tài)對象聲明為靜態(tài)常量, 有幾個狀態(tài)對象就聲明幾個靜態(tài)常量。
          • 環(huán)境角色具有狀態(tài)抽象角色定義的所有行為, 具體執(zhí)行使用委托方式。
          public?class?Client?{
          ????public?static?void?main(String[]?args)?{
          ????????//定義環(huán)境角色
          ????????Context?context?=?new?Context();
          ????????//初始化狀態(tài)
          ????????context.setCurrentState(new?ConcreteState1());
          ????????//行為執(zhí)行
          ????????context.handle1();
          ????????context.handle2();
          ????}
          }

          這里我們已經(jīng)隱藏了狀態(tài)的變化過程, 它的切換引起了行為的變化。對外來說, 我們只看到行為的發(fā)生改變, 而不用知道是狀態(tài)變化引起的。

          3.4 優(yōu)點(diǎn)

          • 避免了過多的 if ? else ?語句的使用,避免了程序的復(fù)雜性,提高系統(tǒng)的可維護(hù)性。
          • 使用多態(tài)代替了條件判斷,這樣我們代碼的擴(kuò)展性更強(qiáng),比如要增加一些狀態(tài),會非常的容易。
          • 狀態(tài)是可以被共享的,狀態(tài)都是由 static final 進(jìn)行修飾的。

          3.5 缺點(diǎn)

          有優(yōu)點(diǎn)的同事也會產(chǎn)生缺點(diǎn),有時候,優(yōu)點(diǎn)和缺點(diǎn)的產(chǎn)生其實(shí)是同一個事實(shí):

          狀態(tài)模式最主要的一個缺點(diǎn)是:子類會太多,也就是類膨脹。因?yàn)橐粋€事物有很多個狀態(tài)也不稀奇,如果完全使用狀態(tài)模式就會有太多的子類,不好管理。

          4. 案例完善

          前面那個 LOL 的例子,如果使用狀態(tài)模式重寫一下,會是這樣的:

          首先創(chuàng)建一個跑動的接口:

          public?interface?RunState?{
          ????void?run(Hero?hero);
          }

          接下來是4個實(shí)現(xiàn)類,分別實(shí)現(xiàn)不同狀態(tài)的跑動結(jié)果:

          public?class?CommonState?implements?RunState?{
          ????@Override
          ????public?void?run(Hero?hero)?{
          ????????//?正常跑動則不打印內(nèi)容,否則會刷屏
          ????}
          }

          public?class?SpeedUpState?implements?RunState{
          ????@Override
          ????public?void?run(Hero?hero)?{
          ????????System.out.println("--------------加速跑動---------------");
          ????????try?{
          ????????????Thread.sleep(2000);//假設(shè)加速持續(xù)2秒
          ????????}?catch?(InterruptedException?e)?{}
          ????????hero.setState(Hero.COMMON);
          ????????System.out.println("------加速狀態(tài)結(jié)束,變?yōu)檎顟B(tài)------");
          ????}
          }

          public?class?SpeedDownState?implements?RunState{
          ????@Override
          ????public?void?run(Hero?hero)?{
          ????????System.out.println("--------------減速跑動---------------");
          ????????try?{
          ????????????Thread.sleep(2000);//假設(shè)減速持續(xù)2秒
          ????????}?catch?(InterruptedException?e)?{}
          ????????hero.setState(Hero.COMMON);
          ????????System.out.println("------減速狀態(tài)結(jié)束,變?yōu)檎顟B(tài)------");
          ????}
          }

          public?class?SwimState?implements?RunState?{
          ????@Override
          ????public?void?run(Hero?hero)?{
          ????????System.out.println("--------------不能跑動---------------");
          ????????try?{
          ????????????Thread.sleep(1000);//假設(shè)眩暈持續(xù)1秒
          ????????}?catch?(InterruptedException?e)?{}
          ????????hero.setState(Hero.COMMON);
          ????????System.out.println("------眩暈狀態(tài)結(jié)束,變?yōu)檎顟B(tài)------");
          ????}
          }

          最后是一個 Hero(Context) 類:

          public?class?Hero?{
          ????public?static?final?RunState?COMMON?=?new?CommonState();//正常狀態(tài)

          ????public?static?final?RunState?SPEED_UP?=?new?SpeedUpState();//加速狀態(tài)

          ????public?static?final?RunState?SPEED_DOWN?=?new?SpeedDownState();//減速狀態(tài)

          ????public?static?final?RunState?SWIM?=?new?SwimState();//眩暈狀態(tài)

          ????private?RunState?state?=?COMMON;//默認(rèn)是正常狀態(tài)

          ????private?Thread?runThread;//跑動線程
          ????//設(shè)置狀態(tài)
          ????public?void?setState(RunState?state)?{
          ????????this.state?=?state;
          ????}
          ????//停止跑動
          ????public?void?stopRun()?{
          ????????if?(isRunning())?runThread.interrupt();
          ????????System.out.println("--------------停止跑動---------------");
          ????}
          ????//開始跑動
          ????public?void?startRun()?{
          ????????if?(isRunning())?{
          ????????????return;
          ????????}
          ????????final?Hero?hero?=?this;
          ????????runThread?=?new?Thread(new?Runnable()?{
          ????????????public?void?run()?{
          ????????????????while?(!runThread.isInterrupted())?{
          ????????????????????state.run(hero);
          ????????????????}
          ????????????}
          ????????});
          ????????System.out.println("--------------開始跑動---------------");
          ????????runThread.start();
          ????}

          ????private?boolean?isRunning(){
          ????????return?runThread?!=?null?&&?!runThread.isInterrupted();
          ????}
          }

          可以看到,這段代碼和開頭那段代碼雖然完成了一樣的功能,但是整個代碼的復(fù)雜度缺以肉眼可見的級別提高了,一般而言,我們犧牲復(fù)雜性去換取的高可維護(hù)性和擴(kuò)展性是相當(dāng)值得的,除非增加了復(fù)雜性以后,對于后者的提升會乎其微。





          感謝閱讀



          瀏覽 25
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(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>
                  黄色片免费视频草逼草逼草逼草逼草逼 | 一级黄色免费在线播放 | 国产欧美日韩在线 | 久久久77777 | 欧洲成人免费视频 |