1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        干掉if-else,試試狀態(tài)模式!

        共 6457字,需瀏覽 13分鐘

         ·

        2022-01-17 02:08

        點(diǎn)擊關(guān)注公眾號(hào),回復(fù)“2T”獲取2TB學(xué)習(xí)資源!

        互聯(lián)網(wǎng)架構(gòu)師后臺(tái)回復(fù) 2T 有特別禮包

        來(lái)源:zhenbianshu.github.io

        上一篇:不卷了!技術(shù)團(tuán)隊(duì)成員集體辭職

        背景


        玩轉(zhuǎn) Java 動(dòng)態(tài)編譯,實(shí)現(xiàn)了 Java 代碼的動(dòng)態(tài)編譯后,接下來(lái)就要將原來(lái)使用注釋配置的 Java 數(shù)據(jù)類型改為使用縮寫(xiě)替代。


        為了便于縮寫(xiě),能直觀地看出完整類型,我設(shè)計(jì)的方案是:



        我使用普通的 if-else 方式和狀態(tài)機(jī)方式各實(shí)現(xiàn)了一遍,更深切地理解了狀態(tài)機(jī)在處理這種多狀態(tài)的復(fù)雜問(wèn)題時(shí)的優(yōu)越性。


        兩種實(shí)現(xiàn)的代碼我都放在了 github 上,地址是:Github-zhenbianshu-java_shorten_type_parser,有類似需求的可以改改來(lái)用。


        IF-ELSE 方式


        原來(lái)以為寫(xiě)一個(gè)簡(jiǎn)單的類型翻譯器花不了太多時(shí)間,可是真做起來(lái),才發(fā)現(xiàn)要注意的點(diǎn)太多了。


        首先是處理容器的開(kāi)啟和閉合,這就需要使用棧來(lái)保存預(yù)期的下一個(gè)字符類型,再對(duì)比棧頂字符類型和當(dāng)前處理字符,決定解析的結(jié)果。


        還要注意類型嵌套的情況下,內(nèi)層嵌套的容器作為外層容器的元素被解析完成時(shí),需要修改外層容器的預(yù)期字符。而且 Map 作為一種相對(duì) Set 和 List 比較特殊的容器,還要處理它的左右元素。


        同時(shí)還不能忘記處理各種異常,如未知字符、容器內(nèi)是原始類型、容器未正確閉合等。


        而這些邏輯混雜在一塊就更添復(fù)雜度了,通常是一遍代碼寫(xiě)下來(lái)挺順暢,找?guī)讉€(gè)特殊的 case 一驗(yàn)證,往往就有沒(méi)有考慮到的點(diǎn),你以為解決了這個(gè)點(diǎn)就好了,殊不知這個(gè)問(wèn)題點(diǎn)的解決方案又引起了另一個(gè)問(wèn)題。


        最終修修補(bǔ)補(bǔ)好多次,終于把代碼寫(xiě)完了,連優(yōu)化的想法都沒(méi)了,擔(dān)心又引入新的問(wèn)題。


        最終的偽代碼如下:


            public String parseToFullType() throws IllegalStateException {        StringBuilder sb = new StringBuilder();

        for (; ; this.scanner.next()) { Character currentChar = scanner.current(); if (currentChar == '\uFFFF') { return sb.toString(); } if (isCollection()) { if (CollectionEnd()) { dealCollectionEleEnd(); }else { throw new IllegalStateException("unexpected char '" + currentChar + "' at position " + scanner.getIndex()); } } else if (isWrapperType()) { dealSingleEleEnd(); } else if (parseStart()) { if (collectionStart()) { putCollecitonExpectEle() } } else { throw new IllegalStateException("unknown char '" + currentChar + "' at position " + scanner.getIndex()); } }

          

        狀態(tài)機(jī)方式


        是不是看起來(lái)非常亂,這還沒(méi)有列出各個(gè)方法里的條件判斷語(yǔ)句呢。這么多邏輯混雜,造成的問(wèn)題就是很難改動(dòng),因?yàn)槟悴恢栏膭?dòng)會(huì)影響哪些其他邏輯。

        面對(duì)這種問(wèn)題,當(dāng)然有一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過(guò)分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié),就是狀態(tài)機(jī)。

        狀態(tài)機(jī)


        有限狀態(tài)機(jī)(finite-state machine,縮寫(xiě):FSM)又稱有限狀態(tài)自動(dòng)機(jī)(finite-state automation,縮寫(xiě):FSA),簡(jiǎn)稱狀態(tài)機(jī),是表示有限個(gè)狀態(tài)以及在這些狀態(tài)之間的轉(zhuǎn)移和動(dòng)作等行為的數(shù)學(xué)計(jì)算模型。


        像我們生活中在公路上駕駛汽車就像在維護(hù)一個(gè)狀態(tài)機(jī),遇到紅燈就停車喝口水,紅燈過(guò)后再繼續(xù)行車,遇到了黃燈就要減速慢行。而實(shí)現(xiàn)狀態(tài)機(jī)前要首先明確四個(gè)主體:

        狀態(tài) State:狀態(tài)是一個(gè)系統(tǒng)在其生命周期的某一刻時(shí)的運(yùn)行狀態(tài),如駕車的例子中狀態(tài)就包括 正常速度行駛、停車和低速行駛?cè)N狀態(tài)。

        事件 Event:事件就是某一時(shí)刻施加于系統(tǒng)的某個(gè)信號(hào),在上面的例子中事件是指紅燈、綠燈和黃燈。所有的狀態(tài)變化都要依賴事件,但事件也可能導(dǎo)致?tīng)顟B(tài)不發(fā)生變化,如正常行駛中遇到綠燈就不用做什么反應(yīng)。

        變換 Transition:變換是在事件發(fā)生之后系統(tǒng)要做出的狀態(tài)變化,如上面例子中的減速、停車或加速。

        動(dòng)作 Action:動(dòng)作是同樣是事件發(fā)生之后系統(tǒng)做出的反應(yīng),不同的是,動(dòng)作不會(huì)改變系統(tǒng)狀態(tài),像駕車遇到紅燈停車后,喝水這個(gè)動(dòng)作沒(méi)有對(duì)系統(tǒng)狀態(tài)造成影響。

        將狀態(tài)機(jī)的四種要素提取之后,就可以很簡(jiǎn)單地將狀態(tài)和事件進(jìn)行解耦了。


        狀態(tài)拆分


        還是拿我的這個(gè)需求來(lái)分析,先畫(huà)出狀態(tài)變化圖從整體上把握狀態(tài)間的關(guān)系。


        通過(guò)上面的圖一步步拆解狀態(tài)機(jī):


        • 首先是確定狀態(tài),我定義了 Start/SetStart/SetEle/ListStart/ListEel/MapStart/MapLeft/MapRight 八種基礎(chǔ)狀態(tài),由于一次只解析一個(gè)類型,容器閉合就代表著解析結(jié)束,所以沒(méi)有對(duì)各個(gè)容器設(shè)置結(jié)束狀態(tài)。又因?yàn)橛袪顟B(tài)嵌套的存在,而一個(gè)狀態(tài)沒(méi)法表達(dá)狀態(tài)機(jī)的準(zhǔn)確狀態(tài),需要使用棧來(lái)存儲(chǔ)整體的解析狀態(tài),我使用這個(gè)棧為空來(lái)代表 End 狀態(tài),又省略了一個(gè)狀態(tài)。另外,搜索公眾號(hào)互聯(lián)網(wǎng)架構(gòu)師回復(fù)關(guān)鍵字"2T”獲取一份驚喜禮包。

         public interface StateHandler {     /**      * @param event 要處理的事件      * @param states 系統(tǒng)整體狀態(tài)      * @param result 解析的結(jié)果      */     void handle(Event event, Stack<State> states, StringBuilder result); }


        代碼示例


        將狀態(tài)機(jī)的各個(gè)要素都抽出來(lái)之后,再分別完善每個(gè) StateHandler 的處理邏輯就行,這部分就非常簡(jiǎn)單了,下面是 MapLeftHandler 的詳情。

        public class MapLeftHandler implements StateHandler {    @Override    public void handle(Event event, Stack<State> states, StringBuilder result) {        // 這里是核心的 Action,將單步解析結(jié)果放到最終結(jié)果內(nèi)        result.append(",");        result.append(event.getParsedVal());

        // 狀態(tài)機(jī)的典型處理方式,處理各種事件發(fā)生在當(dāng)前狀態(tài)時(shí)的邏輯 switch (event.getEventType()) { case MAP: states.push(State.MAP_START); break; case SET: states.push(State.SET_START); break; case LIST: states.push(State.LIST_START); break; case WRAPPED_ELE: // 使用 pop 或 push 修改棧頂狀態(tài)來(lái)修改解析器的整體狀態(tài) states.pop(); states.push(State.MAP_RIGHT); break; case PRIMITIVE_ELE: // 當(dāng)前狀態(tài)不能接受的事件類型要拋異常中斷 throw new IllegalStateException("unexpected primitive char '" + event.getCharacter() + "' at position " + event.getIndex()); default: } }}


        主類內(nèi)的代碼如下:
            public static String parseToFullType(String shortenType) throws IllegalStateException {        StringBuilder result = new StringBuilder();        StringCharacterIterator scanner = new StringCharacterIterator(shortenType);        Stack<State> states = new Stack<>();        states.push(State.START);

        for (; ; scanner.next()) { char currentChar = scanner.current(); if (currentChar == '\uFFFF') { return result.toString(); } // 使用整體狀態(tài)為空來(lái)代表解析結(jié)束 if (states.isEmpty()) { throw new IllegalStateException("unexpected char '" + currentChar + "' at position " + scanner.getIndex()); } // 將字符規(guī)整成事件對(duì)象,有利于參數(shù)的傳遞 Event event = Event.parseToEvent(currentChar, scanner.getIndex()); if (event == null) { throw new IllegalStateException("unknown char '" + currentChar + "' at position " + scanner.getIndex()); }
        // 這里需要一個(gè) Map 來(lái)映射狀態(tài)和狀態(tài)處理器 STATE_TO_HANDLER_MAPPING.get(states.peek()).handle(event, states, result); } }


        小結(jié)


        狀態(tài)模式

        如果你對(duì)設(shè)計(jì)模式較熟的話,會(huì)發(fā)現(xiàn)這不就是狀態(tài)模式嘛。

        有解釋說(shuō),狀態(tài)模式會(huì)將事件類型也再解耦,即 StateHandler 里不只有一個(gè)方法,而是會(huì)有八個(gè)方法,分別為 handleStart,HandleListEle 等,但我覺(jué)得模式并不是定式,稍微的變形是沒(méi)有問(wèn)題的,如果單個(gè)事件類型的處理足夠復(fù)雜,將其再拆分更合理一些。


        代碼結(jié)構(gòu)


        最后,對(duì)比 if-else 實(shí)現(xiàn),從代碼量上來(lái)看,狀態(tài)機(jī)實(shí)現(xiàn)增加了很多,這是解耦的代價(jià),當(dāng)然也有很多重復(fù)代碼的緣故,比如在容器閉合時(shí)校驗(yàn)當(dāng)前容器是否內(nèi)嵌容器,并針對(duì)內(nèi)嵌容器做處理的邏輯就完全一樣,為了代碼清晰我就沒(méi)有再抽取方法。

        從可維護(hù)性上來(lái)說(shuō),狀態(tài)機(jī)實(shí)現(xiàn)由于邏輯拆分比較清晰,在添加或刪除一種狀態(tài)時(shí)比較方便,添加一個(gè)狀態(tài)和狀態(tài)處理器就行,但在添加一種事件類型時(shí)較為復(fù)雜,需要修改所有狀態(tài)處理器里的實(shí)現(xiàn),不過(guò)從整體上來(lái)看是利大于弊的,畢竟代碼清晰易改動(dòng)最重要。

        了解了狀態(tài)機(jī)實(shí)現(xiàn)的固定套路之后,你也可以寫(xiě)出高大上的狀態(tài)機(jī)代碼了,快 Get 起來(lái)替換掉項(xiàng)目里雜亂的 if-else 吧。


        最后,關(guān)注公眾號(hào)互聯(lián)網(wǎng)架構(gòu)師,在后臺(tái)回復(fù):2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全。


        正文結(jié)束


        推薦閱讀 ↓↓↓

        1.心態(tài)崩了!稅前2萬(wàn)4,到手1萬(wàn)4,年終獎(jiǎng)扣稅方式1月1日起施行~

        2.深圳一普通中學(xué)老師工資單曝光,秒殺程序員,網(wǎng)友:敢問(wèn)是哪個(gè)學(xué)校畢業(yè)的?

        3.從零開(kāi)始搭建創(chuàng)業(yè)公司后臺(tái)技術(shù)棧

        4.程序員一般可以從什么平臺(tái)接私活?

        5.清華大學(xué):2021 元宇宙研究報(bào)告!

        6.為什么國(guó)內(nèi) 996 干不過(guò)國(guó)外的 955呢?

        7.這封“領(lǐng)導(dǎo)痛批95后下屬”的郵件,句句扎心!

        8.15張圖看懂瞎忙和高效的區(qū)別!

        瀏覽 37
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            777中文字幕| 成人一级A片| 国产伦乱| 国产精品免费观看视频| 免费无码在线播放| 中文字幕内射| 亚洲精品在线视频观看| 天天干夜夜操| 亚洲久久色| 午夜精品18码视频国产17c| 中文字幕视频一区| 天天日天天操天天干| 成人三级片在线播放| 欧美日韩一区二区在线观看| 99热在线观看免费精品| 久久久高清无码| 一级黄色片网站| 少妇高潮日韩| 看A片在线| 青青激情视频| 国产精品无码久久久久成人app| 欧美精品成人免费片| 久久久精品| 熟妇无码| 日本不卡一区二区| 日本免费黄色电影| 国产成人精品视频免费| 日韩精品视频一区二区| 国产精品欧美一区二区三区苍井空| 无码欧洲| 少妇厨房愉情理伦BD在线观看 | 免费爱爱视频| 日本不卡在线| 国产午夜视频在线观看| 黑人Av| 香蕉视频在线看| 日本特级黄A片免费观看| 亚人精品中文字幕在线观看| 操逼视频网址| 大地资源38页| 亚洲操色| AV怡红院| 男女av免费| 亚洲视频无码在线| 亚洲乱码一区二区三区| 天天激情站| 91熊猫| 一级特黄毛片| 精品三级在线观看| 国产精品自拍在线观看| 中文字幕丰满的翔田千里| 中文色片| 97精品人妻一区二区三区香蕉农| 久久黄色成人视频| 亚洲欧洲久久| 日日夜夜超碰| 日日騒av无码| 亚洲午夜影院在线| 亚洲图片中文字幕| 成人一区二区电影| 男人操女人视频网站| 欧美乱欲视频| www.操B| 日韩AV资源网| 免费v在线观看| 韩国成人免费无码免费视频| 午夜福利av电影| AV777777| 少妇性受XXXX黑人XYX性爽| 一级aa免费视频| 91官网在线观看| 欧美日韩a片| 亚洲中文无码av| 欧美色爽| 欧美综合自拍| 91爱爱·com| 777色色色| 91网站在线播放| 日韩成人影视| 我和岳m愉情XXXⅩ视频| 91黄色视频网站| 最近中文字幕在线中文字幕7| 久久蝌蚪窝| 9色网| 超碰天天爱| 日韩精品三级片| 亚洲操逼片| 亚洲日韩国产AV无码无码精品| 日韩精品人妻中文字幕蜜乳| 91嫖妓站街按摩店老熟女| 在线黄网| 东京热无码视频| 欧美爆操视频| 996热久久| 无码精品人妻一区二区| 国产av电影网| 深爱五月天| 99国产一区| 51妺嘿嘿在线电影免费观看| 91黄色视频在线播放| 日韩欧美成人在线视频| 亚洲成人影音| 三级黄色毛片| 91在线无码精品秘蜜桃入口| 91人妻人人爽人人爽| 日韩一级网站| 天天干天天操天天射| 日韩A片一级无码免费蜜桃| mm131亚洲国产精品久久| 中文字幕免费AV| 麻豆91精品91久久久停运原因| 婷婷五月激情小说| 国产高清AV在线| 伊人大香蕉精品| 三级内射| 国产第一精品| 中文字幕乱码中文字幕电视剧| 无码狠狠躁久久久久久久91| 成人自拍视频在线观看| 乱婬妺妺躁爽A片| 欧美成人精品无码| AV你懂得| 欧美黄色操逼| 欧美va亚洲va| 中文字幕成人影片| 日韩在线成人视频| 久久久久久久无码| 国产在线无码视频| 在线观看日本vs欧洲vs美洲| 久久久在线| 91大长腿美女花外围在线观看| 人人操夜夜| 国产在线视频第一页| 在线观看AV网站| 久久精品999| 久久涩| 91精品国产偷窥一区二区 | 久草社区在线| 操小逼视频| 动漫3D成人H无码国漫| 婷婷五月天色播| 午夜69成人做爱视频网站| 大香蕉伊人AV| 国内成人精品| 高清无码在线看| 欧美footjob高跟脚交| 97色在线视频| 中文无码AV在线| 亚洲无码AV网站| 91精品丝袜久久久久久久久粉嫩| 蜜臀99久久精品久久久久久软件 | 日韩毛片在线看| 一本久久精品一区二区| 一区二区网站| 操碰97| 天堂亚洲AV无码精品成人| 亚洲中文字幕在线观看免费| 四虎亚洲| 丁香五月中文| 91超碰人人操| 大香蕉性爱| 51黄片| 欧美黑人操逼视频| 91精品午夜少妇| 可以免费看的黄色| 男人天堂色| 成人免费a片| 国产免费黄色视频| 国产日韩a| 男人插女人网站| 天堂网AV在线| 成人av天堂| 亚洲成人国产| 中文字幕免| 中文字幕丰满的翔田千里| 亚洲一级性爱| 麻豆午夜成人无码电影| 猫咪成人网站| 四虎无码丰满人妻| 国产黄色视频在线播放| 黄色无码视频在线观看| 国产乱子伦精品免费,| 中文字幕网址在线| 安徽妇搡BBBB搡BBBB小说| 5252a我爱haose01我愿| 韩国无码视频在线观看| 亚洲性片| 荫蒂添出高潮A片视频| 亚洲免费视频在线观看| 韩国一区二区三区在线观看| 亚洲国产欧美在线| 欧美性色网| 日本黄色一级视频| 亚洲天堂AB| 青娱乐国产精品一区二区| 蜜臀久久99精品久久久| 第四色激情网| 免费看一级无码成人片| a级黄色视频免费观看| 日韩欧美大香蕉| 成人性爱在线视频| 亚洲视频在线免费播放| AV黄片| 亚洲综合伊人无码| 国产熟睡乱子伦午夜视频_第1集 | 91精品人妻少妇无码影院| 日本高清一区| 91香蕉视频在线| h在线网站| 少妇搡BBBB搡BBB搡HD(| 97视频在线免费观看| 中文字幕免费高清| 国产91探花| 国产视频入口| 97精品在线视频| 三级视频在线播放| 三级av网站| www.97av| 亚洲精品国产av| 在线免费黄色视频| 欧美特黄AAAAAA| www.人人摸| 国产一级a毛一级a毛视频在线网站| 日韩三级电影| 夜色精品视频| 亚洲AV成人无码AV小说| 欧美视频二区| 97色色得| 手机AV在线观看| 日韩在线中文字幕视频| 国内特级毛片| 国产91黄色| 91人妻无码精品一区二区三区| 久久精品国产99精品国产亚洲性色 | 亚洲香蕉在线| 天天干天天操综合| 人人摸在线视频| 大香蕉伊人AV| 国产亲子乱A片免费视频| 亚洲国产精品18久久久久久| 婷婷五月天大香蕉| 日韩成人网址| 人人肏肏人人| 免费视频爱爱| 精品国产欧美一区二区三区成人 | 亚洲中文视频在线| 四虎日韩| 九九热精品视频在线观看| 国产人国产视频成人免费观看… | 波多野结衣av中文字幕| 久久青| 国产精品黑人ThePorn| ww免费视频| 99久久婷婷国产综合精品hsex,亚| 另类老妇性bbwbbwbbw| 欧美综合自拍| 极品久久久| 综合色国产精品欧美在线| 日韩欧美高清无码| 激情亚洲婷婷| 午夜精品一区二区三区在线视频| 成人在线三级| 伊人看片| 国产无码网站| 亚洲狼人久久久精品| 亚洲无码www| 欧美在线中文字幕| 国产综合色网| 日韩高清无码毛片| 热99精品| 三级视频网址| 青青草原无码| 国产免费自拍| 亚洲AV无码黑人专区| 91麻豆福利视频| 亚洲色图欧美| 久久久久久久久毛片| 免费黄片视频在线观看| 亚洲免费网站| 狠狠噜噜| 四川少扫搡BBBBB搡B| 国产在线欧美在线白浆| 操屄在线观看| 亚洲va国产天堂va久久en| 久久无码免费| 国产家庭乱伦| 女人的天堂av| 日韩无码人妻视频| 成人无码久久| 黄色A级片| 97亚洲国产| 美女天堂网| 青青五月天| 久久国产亚洲| 中文字幕网址在线| 亚洲国产成人无码| 丁香婷婷六月| 大香蕉国产精品| 中国毛片视频| 波多野结衣av在线播放|