乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)狀態(tài)模式「模擬系統(tǒng)營(yíng)銷活動(dòng),狀態(tài)流程審核發(fā)布上線場(chǎng)景」

       小傅哥 2021-12-13


      作者:小傅哥
      博客:https:// - 原創(chuàng)系列專題文章

      沉淀、分享、成長(zhǎng),讓自己和他人都能有所收獲!😄

      文章目錄

      一、前言

      寫好代碼三個(gè)關(guān)鍵點(diǎn)

      如果把寫代碼想象成家里的軟裝,你肯定會(huì)想到家里需要有一個(gè)非常不錯(cuò)格局最好是南北通透的,買回來的家具最好是品牌保證質(zhì)量的,之后呢是大小合適,不能擺放完了看著別扭。那么把這一過程抽象成寫代碼就是需要三個(gè)核心的關(guān)鍵點(diǎn);架構(gòu)(房間的格局)、命名(品牌和質(zhì)量)、注釋(尺寸大小說明書),只有這三個(gè)點(diǎn)都做好才能完成出一套賞心悅目的

      平原走碼🐎易放難收

      上學(xué)期間你寫了多少代碼?上班一年你能寫多少代碼?回家自己學(xué)習(xí)寫了多少代碼?個(gè)人素養(yǎng)的技術(shù)棧地基都是一塊一塊磚碼出來的,寫的越廣越深,根基就越牢固。當(dāng)根基牢固了以后在再上層建設(shè)就變得迎刃而解了,也更容易建設(shè)了。往往最難的就是一層一層階段的突破,突破就像破殼一樣,也像夯實(shí)地基,短時(shí)間看不到成績(jī),也看不出高度。但以后誰能走的穩(wěn),就靠著默默的沉淀。

      技術(shù)傳承的重要性

      可能是現(xiàn)在時(shí)間節(jié)奏太快,一個(gè)需求下來恨不得當(dāng)天就上線(這個(gè)需求很簡(jiǎn)單,怎么實(shí)現(xiàn)我不管,明天上線!),導(dǎo)致團(tuán)隊(duì)的人都很慌、很急、很累很崩潰,最終反反復(fù)復(fù)的人員更替,項(xiàng)目在這個(gè)過程中也交接了N次,文檔不全、代碼混亂、錯(cuò)綜復(fù)雜,誰在后面接手也都只能修修補(bǔ)補(bǔ),就像爛尾樓。這個(gè)沒有傳承、沒有沉淀的項(xiàng)目,很難跟隨業(yè)務(wù)的發(fā)展。最終!根基不牢,一地雞毛。

      二、開發(fā)環(huán)境

      1. JDK 1.8
      2. Idea + Maven
      3. 涉及工程三個(gè),可以通過關(guān)注公眾號(hào)bugstack蟲洞棧,回復(fù)源碼下載獲取(打開獲取的鏈接,找到序號(hào)18)
      工程描述
      itstack-demo-design-19-00場(chǎng)景模擬工程;模擬營(yíng)銷活動(dòng)操作服務(wù)(查詢、審核)
      itstack-demo-design-19-01使用一坨代碼實(shí)現(xiàn)業(yè)務(wù)需求
      itstack-demo-design-19-02通過設(shè)計(jì)模式優(yōu)化改造代碼,產(chǎn)生對(duì)比性從而學(xué)習(xí)

      三、狀態(tài)模式介紹

      狀態(tài)模式,圖片來自 refactoringguru.cn

      狀態(tài)模式描述的是一個(gè)行為下的多種狀態(tài)變更,比如我們最常見的一個(gè)網(wǎng)站的頁面,在你登錄與不登錄下展示的內(nèi)容是略有差異的(不登錄不能展示個(gè)人信息),而這種登錄不登錄就是我們通過改變狀態(tài),而讓整個(gè)行為發(fā)生了變化。

      收音機(jī)&放音機(jī)&磁帶機(jī)

      至少80后、90后的小伙伴基本都用過這種磁帶放音機(jī)(可能沒有這個(gè)好看),它的上面是一排按鈕,當(dāng)放入磁帶后,通過上面的按鈕就可以讓放音機(jī)播放磁帶上的內(nèi)容(listen to 英語聽力考試),而且有些按鈕是互斥的,當(dāng)在某個(gè)狀態(tài)下才可以按另外的按鈕(這在設(shè)計(jì)模式里也是一個(gè)關(guān)鍵的點(diǎn))。

      四、案例場(chǎng)景模擬

      在本案例中我們模擬營(yíng)銷活動(dòng)審核狀態(tài)流轉(zhuǎn)場(chǎng)景(一個(gè)活動(dòng)的上線是多個(gè)層級(jí)審核上線的)

      在上圖中也可以看到我們的流程節(jié)點(diǎn)中包括了各個(gè)狀態(tài)到下一個(gè)狀態(tài)扭轉(zhuǎn)的關(guān)聯(lián)條件,比如;審核通過才能到活動(dòng)中,而不能從編輯中直接到活動(dòng)中,而這些狀態(tài)的轉(zhuǎn)變就是我們要完成的場(chǎng)景處理。

      大部分程序員基本都開發(fā)過類似的業(yè)務(wù)場(chǎng)景,需要對(duì)活動(dòng)或者一些配置需要審核后才能對(duì)外發(fā)布,而這個(gè)審核的過程往往會(huì)隨著系統(tǒng)的重要程度而設(shè)立多級(jí)控制,來保證一個(gè)活動(dòng)可以安全上線,避免造成資損。

      當(dāng)然有時(shí)候會(huì)用到一些審批流的過程配置,也是非常方便開發(fā)類似的流程的,也可以在配置中設(shè)定某個(gè)節(jié)點(diǎn)的審批人員。但這不是我們主要體現(xiàn)的點(diǎn),在本案例中我們主要是模擬學(xué)習(xí)對(duì)一個(gè)活動(dòng)的多個(gè)狀態(tài)節(jié)點(diǎn)的審核控制。

      1. 場(chǎng)景模擬工程

      itstack-demo-design-19-00
      └── src
          └── main
              └── java
                  └── org.itstack.demo.design
                      ├── ActivityInfo.java
                      ├── Status.java
                      └── ActivityService.java
      
      • 在這個(gè)模擬工程里我們提供了三個(gè)類,包括;狀態(tài)枚舉(Status)、活動(dòng)對(duì)象(ActivityInfo)、活動(dòng)服務(wù)(ActivityService),三個(gè)服務(wù)類。
      • 接下來我們就分別介紹三個(gè)類包括的內(nèi)容。

      2. 代碼實(shí)現(xiàn)

      2.1 基本活動(dòng)信息

      public class ActivityInfo {
      
          private String activityId;    // 活動(dòng)ID
          private String activityName;  // 活動(dòng)名稱
          private Enum<Status> status;  // 活動(dòng)狀態(tài)
          private Date beginTime;       // 開始時(shí)間
          private Date endTime;         // 結(jié)束時(shí)間
         
          // ...get/set
      }  
      
      • 一些基本的活動(dòng)信息;活動(dòng)ID、活動(dòng)名稱、活動(dòng)狀態(tài)、開始時(shí)間、結(jié)束時(shí)間。

      2.2 活動(dòng)枚舉狀態(tài)

      public enum Status {
      
          // 1創(chuàng)建編輯、2待審核、3審核通過(任務(wù)掃描成活動(dòng)中)、4審核拒絕(可以撤審到編輯狀態(tài))、5活動(dòng)中、6活動(dòng)關(guān)閉、7活動(dòng)開啟(任務(wù)掃描成活動(dòng)中)
          Editing, Check, Pass, Refuse, Doing, Close, Open
      
      }
      
      • 活動(dòng)的枚舉;1創(chuàng)建編輯、2待審核、3審核通過(任務(wù)掃描成活動(dòng)中)、4審核拒絕(可以撤審到編輯狀態(tài))、5活動(dòng)中、6活動(dòng)關(guān)閉、7活動(dòng)開啟(任務(wù)掃描成活動(dòng)中)

      2.3 活動(dòng)服務(wù)接口

      public class ActivityService {
      
          private static Map<String, Enum<Status>> statusMap = new ConcurrentHashMap<String, Enum<Status>>();
      
          public static void init(String activityId, Enum<Status> status) {
              // 模擬查詢活動(dòng)信息
              ActivityInfo activityInfo = new ActivityInfo();
              activityInfo.setActivityId(activityId);
              activityInfo.setActivityName("早起學(xué)習(xí)打卡領(lǐng)獎(jiǎng)活動(dòng)");
              activityInfo.setStatus(status);
              activityInfo.setBeginTime(new Date());
              activityInfo.setEndTime(new Date());
              statusMap.put(activityId, status);
          }
      
          /**
           * 查詢活動(dòng)信息
           *
           * @param activityId 活動(dòng)ID
           * @return 查詢結(jié)果
           */
          public static ActivityInfo queryActivityInfo(String activityId) {
              // 模擬查詢活動(dòng)信息
              ActivityInfo activityInfo = new ActivityInfo();
              activityInfo.setActivityId(activityId);
              activityInfo.setActivityName("早起學(xué)習(xí)打卡領(lǐng)獎(jiǎng)活動(dòng)");
              activityInfo.setStatus(statusMap.get(activityId));
              activityInfo.setBeginTime(new Date());
              activityInfo.setEndTime(new Date());
              return activityInfo;
          }
      
          /**
           * 查詢活動(dòng)狀態(tài)
           *
           * @param activityId 活動(dòng)ID
           * @return 查詢結(jié)果
           */
          public static Enum<Status> queryActivityStatus(String activityId) {
              return statusMap.get(activityId);
          }
      
          /**
           * 執(zhí)行狀態(tài)變更
           *
           * @param activityId   活動(dòng)ID
           * @param beforeStatus 變更前狀態(tài)
           * @param afterStatus  變更后狀態(tài) b
           */
          public static synchronized void execStatus(String activityId, Enum<Status> beforeStatus, Enum<Status> afterStatus) {
              if (!beforeStatus.equals(statusMap.get(activityId))) return;
              statusMap.put(activityId, afterStatus);
          }
      
      }
      
      • 在這個(gè)靜態(tài)類中提供了活動(dòng)的查詢和狀態(tài)變更接口;queryActivityInfo、queryActivityStatusexecStatus。
      • 同時(shí)使用Map的結(jié)構(gòu)來記錄活動(dòng)ID和狀態(tài)變化信息,另外還有init方法來初始化活動(dòng)數(shù)據(jù)。實(shí)際的開發(fā)中這類信息基本都是從數(shù)據(jù)庫或者Redis中獲取。

      五、用一坨坨代碼實(shí)現(xiàn)

      這里我們先使用最粗暴的方式來實(shí)現(xiàn)功能

      對(duì)于這樣各種狀態(tài)的變更,最讓我們直接想到的就是使用ifelse進(jìn)行判斷處理。每一個(gè)狀態(tài)可以流轉(zhuǎn)到下一個(gè)什么狀態(tài),都可以使用嵌套的if實(shí)現(xiàn)。

      1. 工程結(jié)構(gòu)

      itstack-demo-design-19-01
      └── src
          └── main
              └── java
                  └── org.itstack.demo.design
                      ├── ActivityExecStatusController.java
                      └── Result.java
      
      • 整個(gè)實(shí)現(xiàn)的工程結(jié)構(gòu)比較簡(jiǎn)單,只包括了兩個(gè)類;ActivityExecStatusController、Result,一個(gè)是處理流程狀態(tài),另外一個(gè)是返回的對(duì)象。

      2. 代碼實(shí)現(xiàn)

      public class ActivityExecStatusController {
      
          /**
           * 活動(dòng)狀態(tài)變更
           * 1. 編輯中 -> 提審、關(guān)閉
           * 2. 審核通過 -> 拒絕、關(guān)閉、活動(dòng)中
           * 3. 審核拒絕 -> 撤審、關(guān)閉
           * 4. 活動(dòng)中 -> 關(guān)閉
           * 5. 活動(dòng)關(guān)閉 -> 開啟
           * 6. 活動(dòng)開啟 -> 關(guān)閉
           *
           * @param activityId   活動(dòng)ID
           * @param beforeStatus 變更前狀態(tài)
           * @param afterStatus  變更后狀態(tài)
           * @return 返回結(jié)果
           */
          public Result execStatus(String activityId, Enum<Status> beforeStatus, Enum<Status> afterStatus) {
      
              // 1. 編輯中 -> 提審、關(guān)閉
              if (Status.Editing.equals(beforeStatus)) {
                  if (Status.Check.equals(afterStatus) || Status.Close.equals(afterStatus)) {
                      ActivityService.execStatus(activityId, beforeStatus, afterStatus);
                      return new Result("0000", "變更狀態(tài)成功");
                  } else {
                      return new Result("0001", "變更狀態(tài)拒絕");
                  }
              }
      
              // 2. 審核通過 -> 拒絕、關(guān)閉、活動(dòng)中
              if (Status.Pass.equals(beforeStatus)) {
                  if (Status.Refuse.equals(afterStatus) || Status.Doing.equals(afterStatus) || Status.Close.equals(afterStatus)) {
                      ActivityService.execStatus(activityId, beforeStatus, afterStatus);
                      return new Result("0000", "變更狀態(tài)成功");
                  } else {
                      return new Result("0001", "變更狀態(tài)拒絕");
                  }
              }
      
              // 3. 審核拒絕 -> 撤審、關(guān)閉
              if (Status.Refuse.equals(beforeStatus)) {
                  if (Status.Editing.equals(afterStatus) || Status.Close.equals(afterStatus)) {
                      ActivityService.execStatus(activityId, beforeStatus, afterStatus);
                      return new Result("0000", "變更狀態(tài)成功");
                  } else {
                      return new Result("0001", "變更狀態(tài)拒絕");
                  }
              }
      
              // 4. 活動(dòng)中 -> 關(guān)閉
              if (Status.Doing.equals(beforeStatus)) {
                  if (Status.Close.equals(afterStatus)) {
                      ActivityService.execStatus(activityId, beforeStatus, afterStatus);
                      return new Result("0000", "變更狀態(tài)成功");
                  } else {
                      return new Result("0001", "變更狀態(tài)拒絕");
                  }
              }
      
              // 5. 活動(dòng)關(guān)閉 -> 開啟
              if (Status.Close.equals(beforeStatus)) {
                  if (Status.Open.equals(afterStatus)) {
                      ActivityService.execStatus(activityId, beforeStatus, afterStatus);
                      return new Result("0000", "變更狀態(tài)成功");
                  } else {
                      return new Result("0001", "變更狀態(tài)拒絕");
                  }
              }
      
              // 6. 活動(dòng)開啟 -> 關(guān)閉
              if (Status.Open.equals(beforeStatus)) {
                  if (Status.Close.equals(afterStatus)) {
                      ActivityService.execStatus(activityId, beforeStatus, afterStatus);
                      return new Result("0000", "變更狀態(tài)成功");
                  } else {
                      return new Result("0001", "變更狀態(tài)拒絕");
                  }
              }
      
              return new Result("0001", "非可處理的活動(dòng)狀態(tài)變更");
      
          }
      
      }
      
      • 這里我們只需要看一下代碼實(shí)現(xiàn)的結(jié)構(gòu)即可。從上到下是一整篇的ifelse,基本這也是大部分初級(jí)程序員的開發(fā)方式。
      • 這樣的面向過程式開發(fā)方式,對(duì)于不需要改動(dòng)代碼,也不需要二次迭代的,還是可以使用的(但基本不可能不迭代)。而且隨著狀態(tài)和需求變化,會(huì)越來越難以維護(hù),后面的人也不好看懂并且很容易填充其他的流程進(jìn)去。越來越亂就是從點(diǎn)滴開始的

      3. 測(cè)試驗(yàn)證

      3.1 編寫測(cè)試類

      @Test
      public void test() {
          // 初始化數(shù)據(jù)
          String activityId = "100001";
          ActivityService.init(activityId, Status.Editing);  
      
          ActivityExecStatusController activityExecStatusController = new ActivityExecStatusController();
          Result resultRefuse = activityExecStatusController.execStatus(activityId, Status.Editing, Status.Refuse); 
          logger.info("測(cè)試結(jié)果(編輯中To審核拒絕):{}", JSON.toJSONString(resultRefuse));                           
      
          Result resultCheck = activityExecStatusController.execStatus(activityId, Status.Editing, Status.Check);
          logger.info("測(cè)試結(jié)果(編輯中To提交審核):{}", JSON.toJSONString(resultCheck));
      }
      
      • 我們的測(cè)試代碼包括了兩個(gè)功能的驗(yàn)證,一個(gè)是從編輯中審核拒絕,另外一個(gè)是從編輯中到提交審核。
      • 因?yàn)閺奈覀兊膱?chǎng)景流程中可以看到,編輯中的活動(dòng)是不能直接到審核拒絕的,這中間還需要提審。

      3.2 測(cè)試結(jié)果

      23:24:30.774 [main] INFO  org.itstack.demo.design.test.ApiTest - 測(cè)試結(jié)果(編輯中To審核拒絕){"code":"0001","info":"變更狀態(tài)拒絕"}
      23:24:30.778 [main] INFO  org.itstack.demo.design.test.ApiTest - 測(cè)試結(jié)果(編輯中To提交審核){"code":"0000","info":"變更狀態(tài)成功"}
      
      Process finished with exit code 0
      
      • 從測(cè)試結(jié)果和我們的狀態(tài)流程的流轉(zhuǎn)中可以看到,是符合測(cè)試結(jié)果預(yù)期的。除了不好維護(hù)外,這樣的開發(fā)過程還是蠻快的,但不建議這么搞!

      六、狀態(tài)模式重構(gòu)代碼

      接下來使用狀態(tài)模式來進(jìn)行代碼優(yōu)化,也算是一次很小的重構(gòu)。

      重構(gòu)的重點(diǎn)往往是處理掉ifelse,而想處理掉ifelse基本離不開接口抽象類,另外還需要重新改造代碼結(jié)構(gòu)。

      1. 工程結(jié)構(gòu)

      itstack-demo-design-19-02
      └── src
          └── main
              └── java
                  └── org.itstack.demo.design
                      ├── event
                      │    ├── CheckState.java
                      │    └── CloseState.java
                      │    └── DoingState.java
                      │    └── EditingState.java
                      │    └── OpenState.java
                      │    └── PassState.java
                      │    └── RefuseState.java
                      ├── Result.java
                      ├── State.java
                      └── StateHandler.java
      

      狀態(tài)模式模型結(jié)構(gòu)

      狀態(tài)模式模型結(jié)構(gòu)

      • 以上是狀態(tài)模式的整個(gè)工程結(jié)構(gòu)模型,State是一個(gè)抽象類,定義了各種操作接口(提審、審核、拒審等)。
      • 右側(cè)的不同顏色狀態(tài)與我們場(chǎng)景模擬中的顏色保持一致,是各種狀態(tài)流程流轉(zhuǎn)的實(shí)現(xiàn)操作。這里的實(shí)現(xiàn)有一個(gè)關(guān)鍵點(diǎn)就是每一種狀態(tài)到下一個(gè)狀態(tài),都分配到各個(gè)實(shí)現(xiàn)方法中控制,也就不需要if語言進(jìn)行判斷了。
      • 最后是StateHandler對(duì)狀態(tài)流程的統(tǒng)一處理,里面提供Map結(jié)構(gòu)的各項(xiàng)服務(wù)接口調(diào)用,也就避免了使用if判斷各項(xiàng)狀態(tài)轉(zhuǎn)變的流程。

      2. 代碼實(shí)現(xiàn)

      2.1 定義狀態(tài)抽象類

      public abstract class State {
      
          /**
           * 活動(dòng)提審
           *
           * @param activityId    活動(dòng)ID
           * @param currentStatus 當(dāng)前狀態(tài)
           * @return 執(zhí)行結(jié)果
           */
          public abstract Result arraignment(String activityId, Enum<Status> currentStatus);
      
          /**
           * 審核通過
           *
           * @param activityId    活動(dòng)ID
           * @param currentStatus 當(dāng)前狀態(tài)
           * @return 執(zhí)行結(jié)果
           */
          public abstract Result checkPass(String activityId, Enum<Status> currentStatus);
      
          /**
           * 審核拒絕
           *
           * @param activityId    活動(dòng)ID
           * @param currentStatus 當(dāng)前狀態(tài)
           * @return 執(zhí)行結(jié)果
           */
          public abstract Result checkRefuse(String activityId, Enum<Status> currentStatus);
      
          /**
           * 撤審撤銷
           *
           * @param activityId    活動(dòng)ID
           * @param currentStatus 當(dāng)前狀態(tài)
           * @return 執(zhí)行結(jié)果
           */
          public abstract Result checkRevoke(String activityId, Enum<Status> currentStatus);
      
          /**
           * 活動(dòng)關(guān)閉
           *
           * @param activityId    活動(dòng)ID
           * @param currentStatus 當(dāng)前狀態(tài)
           * @return 執(zhí)行結(jié)果
           */
          public abstract Result close(String activityId, Enum<Status> currentStatus);
      
          /**
           * 活動(dòng)開啟
           *
           * @param activityId    活動(dòng)ID
           * @param currentStatus 當(dāng)前狀態(tài)
           * @return 執(zhí)行結(jié)果
           */
          public abstract Result open(String activityId, Enum<Status> currentStatus);
      
          /**
           * 活動(dòng)執(zhí)行
           *
           * @param activityId    活動(dòng)ID
           * @param currentStatus 當(dāng)前狀態(tài)
           * @return 執(zhí)行結(jié)果
           */
          public abstract Result doing(String activityId, Enum<Status> currentStatus);
      
      }
      
      • 在整個(gè)接口中提供了各項(xiàng)狀態(tài)流轉(zhuǎn)服務(wù)的接口,例如;活動(dòng)提審、審核通過、審核拒絕、撤審撤銷等7個(gè)方法。
      • 在這些方法中所有的入?yún)⒍际且粯拥?#xff0c;activityId(活動(dòng)ID)、currentStatus(當(dāng)前狀態(tài)),只有他們的具體實(shí)現(xiàn)是不同的。

      2.2 部分狀態(tài)流轉(zhuǎn)實(shí)現(xiàn)

      編輯

      public class EditingState extends State {
      
          public Result arraignment(String activityId, Enum<Status> currentStatus) {
              ActivityService.execStatus(activityId, currentStatus, Status.Check);
              return new Result("0000", "活動(dòng)提審成功");
          }
      
          public Result checkPass(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "編輯中不可審核通過");
          }
      
          public Result checkRefuse(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "編輯中不可審核拒絕");
          }
      
          @Override
          public Result checkRevoke(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "編輯中不可撤銷審核");
          }
      
          public Result close(String activityId, Enum<Status> currentStatus) {
              ActivityService.execStatus(activityId, currentStatus, Status.Close);
              return new Result("0000", "活動(dòng)關(guān)閉成功");
          }
      
          public Result open(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "非關(guān)閉活動(dòng)不可開啟");
          }
      
          public Result doing(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "編輯中活動(dòng)不可執(zhí)行活動(dòng)中變更");
          }
      
      }
      

      提審

      public class CheckState extends State {
      
          public Result arraignment(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "待審核狀態(tài)不可重復(fù)提審");
          }
      
          public Result checkPass(String activityId, Enum<Status> currentStatus) {
              ActivityService.execStatus(activityId, currentStatus, Status.Pass);
              return new Result("0000", "活動(dòng)審核通過完成");
          }
      
          public Result checkRefuse(String activityId, Enum<Status> currentStatus) {
              ActivityService.execStatus(activityId, currentStatus, Status.Refuse);
              return new Result("0000", "活動(dòng)審核拒絕完成");
          }
      
          @Override
          public Result checkRevoke(String activityId, Enum<Status> currentStatus) {
              ActivityService.execStatus(activityId, currentStatus, Status.Editing);
              return new Result("0000", "活動(dòng)審核撤銷回到編輯中");
          }
      
          public Result close(String activityId, Enum<Status> currentStatus) {
              ActivityService.execStatus(activityId, currentStatus, Status.Close);
              return new Result("0000", "活動(dòng)審核關(guān)閉完成");
          }
      
          public Result open(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "非關(guān)閉活動(dòng)不可開啟");
          }
      
          public Result doing(String activityId, Enum<Status> currentStatus) {
              return new Result("0001", "待審核活動(dòng)不可執(zhí)行活動(dòng)中變更");
          }
      
      }
      
      • 這里提供了兩個(gè)具體實(shí)現(xiàn)類的內(nèi)容,編輯狀態(tài)和提審狀態(tài)。
      • 例如在這兩個(gè)實(shí)現(xiàn)類中,checkRefuse這個(gè)方法對(duì)于不同的類中有不同的實(shí)現(xiàn),也就是不同狀態(tài)下能做的下一步流轉(zhuǎn)操作已經(jīng)可以在每一個(gè)方法中具體控制了。
      • 其他5個(gè)類的操作是類似的具體就不在這里演示了,大部分都是重復(fù)代碼??梢酝ㄟ^源碼進(jìn)行學(xué)習(xí)理解。

      2.3 狀態(tài)處理服務(wù)

      public class StateHandler {
      
          private Map<Enum<Status>, State> stateMap = new ConcurrentHashMap<Enum<Status>, State>();
      
          public StateHandler() {
              stateMap.put(Status.Check, new CheckState());     // 待審核
              stateMap.put(Status.Close, new CloseState());     // 已關(guān)閉
              stateMap.put(Status.Doing, new DoingState());     // 活動(dòng)中
              stateMap.put(Status.Editing, new EditingState()); // 編輯中
              stateMap.put(Status.Open, new OpenState());       // 已開啟
              stateMap.put(Status.Pass, new PassState());       // 審核通過
              stateMap.put(Status.Refuse, new RefuseState());   // 審核拒絕
          }
      
          public Result arraignment(String activityId, Enum<Status> currentStatus) {
              return stateMap.get(currentStatus).arraignment(activityId, currentStatus);
          }
      
          public Result checkPass(String activityId, Enum<Status> currentStatus) {
              return stateMap.get(currentStatus).checkPass(activityId, currentStatus);
          }
      
          public Result checkRefuse(String activityId, Enum<Status> currentStatus) {
              return stateMap.get(currentStatus).checkRefuse(activityId, currentStatus);
          }
      
          public Result checkRevoke(String activityId, Enum<Status> currentStatus) {
              return stateMap.get(currentStatus).checkRevoke(activityId, currentStatus);
          }
      
          public Result close(String activityId, Enum<Status> currentStatus) {
              return stateMap.get(currentStatus).close(activityId, currentStatus);
          }
      
          public Result open(String activityId, Enum<Status> currentStatus) {
              return stateMap.get(currentStatus).open(activityId, currentStatus);
          }
      
          public Result doing(String activityId, Enum<Status> currentStatus) {
              return stateMap.get(currentStatus).doing(activityId, currentStatus);
          }
          
      }
      
      • 這是對(duì)狀態(tài)服務(wù)的統(tǒng)一控制中心,可以看到在構(gòu)造函數(shù)中提供了所有狀態(tài)和實(shí)現(xiàn)的具體關(guān)聯(lián),放到Map數(shù)據(jù)結(jié)構(gòu)中。
      • 同時(shí)提供了不同名稱的接口操作類,讓外部調(diào)用方可以更加容易的使用此項(xiàng)功能接口,而不需要像在itstack-demo-design-19-01例子中還得傳兩個(gè)狀態(tài)來判斷。

      3. 測(cè)試驗(yàn)證

      3.1 編寫測(cè)試類(Editing2Arraignment)

      @Test
      public void test_Editing2Arraignment() {
          String activityId = "100001";
          ActivityService.init(activityId, Status.Editing);
          StateHandler stateHandler = new StateHandler();
          Result result = stateHandler.arraignment(activityId, Status.Editing);
          logger.info("測(cè)試結(jié)果(編輯中To提審活動(dòng)):{}", JSON.toJSONString(result));
          logger.info("活動(dòng)信息:{} 狀態(tài):{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
      }
      

      測(cè)試結(jié)果

      23:59:20.883 [main] INFO  org.itstack.demo.design.test.ApiTest - 測(cè)試結(jié)果(編輯中To提審活動(dòng)){"code":"0000","info":"活動(dòng)提審成功"}
      23:59:20.907 [main] INFO  org.itstack.demo.design.test.ApiTest - 活動(dòng)信息:{"activityId":"100001","activityName":"早起學(xué)習(xí)打卡領(lǐng)獎(jiǎng)活動(dòng)","beginTime":1593694760892,"endTime":1593694760892,"status":"Check"} 狀態(tài):"Check"
      
      Process finished with exit code 0
      
      • 測(cè)試編輯中To提審活動(dòng),的狀態(tài)流轉(zhuǎn)。

      3.2 編寫測(cè)試類(Editing2Open)

      @Test
      public void test_Editing2Open() {
          String activityId = "100001";
          ActivityService.init(activityId, Status.Editing);
          StateHandler stateHandler = new StateHandler();
          Result result = stateHandler.open(activityId, Status.Editing);
          logger.info("測(cè)試結(jié)果(編輯中To開啟活動(dòng)):{}", JSON.toJSONString(result));
          logger.info("活動(dòng)信息:{} 狀態(tài):{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
      }
      

      測(cè)試結(jié)果

      23:59:36.904 [main] INFO  org.itstack.demo.design.test.ApiTest - 測(cè)試結(jié)果(編輯中To開啟活動(dòng)){"code":"0001","info":"非關(guān)閉活動(dòng)不可開啟"}
      23:59:36.914 [main] INFO  org.itstack.demo.design.test.ApiTest - 活動(dòng)信息:{"activityId":"100001","activityName":"早起學(xué)習(xí)打卡領(lǐng)獎(jiǎng)活動(dòng)","beginTime":1593694776907,"endTime":1593694776907,"status":"Editing"} 狀態(tài):"Editing"
      
      Process finished with exit code 0
      
      • 測(cè)試編輯中To開啟活動(dòng),的狀態(tài)流轉(zhuǎn)。

      3.3 編寫測(cè)試類(Refuse2Doing)

      @Test
      public void test_Refuse2Doing() {
          String activityId = "100001";
          ActivityService.init(activityId, Status.Refuse);
          StateHandler stateHandler = new StateHandler();
          Result result = stateHandler.doing(activityId, Status.Refuse);
          logger.info("測(cè)試結(jié)果(拒絕To活動(dòng)中):{}", JSON.toJSONString(result));
          logger.info("活動(dòng)信息:{} 狀態(tài):{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
      }
      

      測(cè)試結(jié)果

      23:59:46.339 [main] INFO  org.itstack.demo.design.test.ApiTest - 測(cè)試結(jié)果(拒絕To活動(dòng)中){"code":"0001","info":"審核拒絕不可執(zhí)行活動(dòng)為進(jìn)行中"}
      23:59:46.352 [main] INFO  org.itstack.demo.design.test.ApiTest - 活動(dòng)信息:{"activityId":"100001","activityName":"早起學(xué)習(xí)打卡領(lǐng)獎(jiǎng)活動(dòng)","beginTime":1593694786342,"endTime":1593694786342,"status":"Refuse"} 狀態(tài):"Refuse"
      
      Process finished with exit code 0
      
      • 測(cè)試拒絕To活動(dòng)中,的狀態(tài)流轉(zhuǎn)。

      3.4 編寫測(cè)試類(Refuse2Revoke)

      @Test
      public void test_Refuse2Revoke() {
          String activityId = "100001";
          ActivityService.init(activityId, Status.Refuse);
          StateHandler stateHandler = new StateHandler();
          Result result = stateHandler.checkRevoke(activityId, Status.Refuse);
          logger.info("測(cè)試結(jié)果(拒絕To撤審):{}", JSON.toJSONString(result));
          logger.info("活動(dòng)信息:{} 狀態(tài):{}", JSON.toJSONString(ActivityService.queryActivityInfo(activityId)), JSON.toJSONString(ActivityService.queryActivityInfo(activityId).getStatus()));
      }
      

      測(cè)試結(jié)果

      23:59:50.197 [main] INFO  org.itstack.demo.design.test.ApiTest - 測(cè)試結(jié)果(拒絕To撤審){"code":"0000","info":"撤銷審核完成"}
      23:59:50.208 [main] INFO  org.itstack.demo.design.test.ApiTest - 活動(dòng)信息:{"activityId":"100001","activityName":"早起學(xué)習(xí)打卡領(lǐng)獎(jiǎng)活動(dòng)","beginTime":1593694810201,"endTime":1593694810201,"status":"Editing"} 狀態(tài):"Editing"
      
      Process finished with exit code 0
      
      • 測(cè)試測(cè)試結(jié)果(拒絕To撤審),的狀態(tài)流轉(zhuǎn)。

      • 綜上以上四個(gè)測(cè)試類分別模擬了不同狀態(tài)之間的有效流轉(zhuǎn)拒絕流轉(zhuǎn),不同的狀態(tài)服務(wù)處理不同的服務(wù)內(nèi)容。

      七、總結(jié)

      • 從以上的兩種方式對(duì)一個(gè)需求的實(shí)現(xiàn)中可以看到,在第二種使用設(shè)計(jì)模式處理后已經(jīng)沒有了ifelse,代碼的結(jié)構(gòu)也更加清晰易于擴(kuò)展。這就是設(shè)計(jì)模式的好處,可以非常強(qiáng)大的改變?cè)写a的結(jié)構(gòu),讓以后的擴(kuò)展和維護(hù)都變得容易些。
      • 在實(shí)現(xiàn)結(jié)構(gòu)的編碼方式上可以看到這不再是面向過程的編程,而是面向?qū)ο蟮慕Y(jié)構(gòu)。并且這樣的設(shè)計(jì)模式滿足了單一職責(zé)開閉原則,當(dāng)你只有滿足這樣的結(jié)構(gòu)下才會(huì)發(fā)現(xiàn)代碼的擴(kuò)展是容易的,也就是增加和修改功能不會(huì)影響整體的變化。
      • 但如果狀態(tài)和各項(xiàng)流轉(zhuǎn)較多像本文的案例中,就會(huì)產(chǎn)生較多的實(shí)現(xiàn)類。因此可能也會(huì)讓代碼的實(shí)現(xiàn)上帶來了時(shí)間成本,因?yàn)槿绻龅竭@樣的場(chǎng)景可以按需評(píng)估投入回報(bào)率。主要點(diǎn)在于看是否經(jīng)常修改、是否可以做成組件化、抽離業(yè)務(wù)與非業(yè)務(wù)功能。

      八、推薦閱讀

      • 1. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)工廠方法模式「多種類型商品不同接口,統(tǒng)一發(fā)獎(jiǎng)服務(wù)搭建場(chǎng)景」
      • 2. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)原型模式「上機(jī)考試多套試,每人題目和答案亂序排列場(chǎng)景」
      • 3. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)橋接模式「多支付渠道(微信、支付寶)與多支付模式(刷臉、指紋)場(chǎng)景」
      • 4. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)組合模式「營(yíng)銷差異化人群發(fā)券,決策樹引擎搭建場(chǎng)景」
      • 5. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)外觀模式「基于SpringBoot開發(fā)門面模式中間件,統(tǒng)一控制接口白名單場(chǎng)景」
      • 6. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)享元模式「基于Redis秒殺,提供活動(dòng)與庫存信息查詢場(chǎng)景」
      • 7. 重學(xué) Java 設(shè)計(jì)模式:實(shí)戰(zhàn)備忘錄模式「模擬互聯(lián)網(wǎng)系統(tǒng)上線過程中,配置文件回滾場(chǎng)景」

        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多