訂單之狀態機

訂單和支付系列目錄

意義

  • 訂單系統各類訂單類型的流轉,觸發事件、執行事件若是不利用狀態機代碼會變得更加複雜且難以維護
  • 經過狀態機,可以把狀態流轉的概念抽象出來,更符合java編程思想的規範
  • 狀態機可以反映時序的布進控制

基礎概念

  • 網絡上關於狀態機的定義有很是多的理論解釋,在這裏筆者僅僅按照本身的理解儘量的簡要描述
  • 例如訂單支付 訂單由待支付狀態(現態),執行了支付(事件),訂單進行了狀態更新(動做)最終變爲已支付的狀態(次態)就是一個完整的狀態機流程

簡要設計

簡要回顧上一篇文章簡易版訂單系統定義的幾個初始狀態java

  • 圖中綠色表明訂單的終態,不一樣類型的訂單系統終態可能不一致,例如商城類訂單已退款就可能不能再繼續操做。商旅類訂單退款以後還能繼續再往下走,這些場景都須要根據實際業務場景來設計訂單的終態部分。
  • 其中每一步的事件流向也須要系統設計者因地制宜,筆者建議結合訂單子狀態對一些模糊狀態進行區分,例如訂單取消分爲主動取消和被動取消,訂單退款分爲部分退款和全額退款等等

代碼設計

  • 秉着不重複造輪子的原則,筆者以前訂單系統主要借鑑了hadoop yarn狀態機的設計,並進行了一點小小的優化和封裝編程

  • yarn狀態機多弧過渡部分由於沒有用到直接省略(感興趣的同窗能夠本身去查看源碼,筆者認爲多弧過渡主要是次態的可選擇性,可是反而增長了不肯定性因此沒有采用)接下來的部分主要是源碼解析網絡

  • 狀態機主要類圖以下app

  • hadoop底層代碼oop

//此方法在addTransition方法中調用 主要是構建鏈表
private StateMachineFactory (StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT> that, ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT> t) {
    this.defaultInitialState = that.defaultInitialState;
    this.transitionsListNode 
        = new TransitionsListNode(t, that.transitionsListNode);
    this.optimized = false;
    this.stateMachineTable = null;
}
//installTopology 中調用進行初始化過程 主要邏輯封裝在makeStateMachineTable()方法中
private StateMachineFactory (StateMachineFactory<OPERAND, STATE, EVENTTYPE, EVENT> that, boolean optimized) {
    this.defaultInitialState = that.defaultInitialState;
    this.transitionsListNode = that.transitionsListNode;
    this.optimized = optimized;
    if (optimized) {
      makeStateMachineTable();
    } else {
      stateMachineTable = null;
    }
}
  
//
private void makeStateMachineTable() {

//建立堆棧 ApplicableTransition將此前鏈表的各個ApplicableTransition壓入棧中
    Stack<ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT>> stack =
      new Stack<ApplicableTransition<OPERAND, STATE, EVENTTYPE, EVENT>>();

    Map<STATE, Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>
      prototype = new HashMap<STATE, Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>();

    prototype.put(defaultInitialState, null);//默認狀態

    // 構建拓撲表 每一個狀態都有一個對應的
    stateMachineTable
       = new EnumMap<STATE, Map<EVENTTYPE,
                           Transition<OPERAND, STATE, EVENTTYPE, EVENT>>>(prototype);

    for (TransitionsListNode cursor = transitionsListNode;
         cursor != null;
         cursor = cursor.next) {
      stack.push(cursor.transition);
    }
 //apply方法就是完整構建拓撲表過程 此處簡要描述 在拓撲表中找到當前訂單狀態的動做映射map,而後把動做放入此map中
    while (!stack.isEmpty()) {
      stack.pop().apply(this);
     
    }
  }
複製代碼
  • 應用層面代碼
//建立一個初始狀態機
private static final StateMachineFactory<OrderRequest, OrderStatusEnum, OrderEvent.OrderEventEnum, OrderEvent> stateMachineFactory = new StateMachineFactory<OrderRequest, OrderStatusEnum, OrderEvent.OrderEventEnum, OrderEvent>(OrderStatusEnum.INVALID)
//調用私有構造方法 添加單弧事件去transitionsListNode
.addTransition(OrderStatusEnum.INVALID, OrderStatusEnum.SUBMIT_ORDER, OrderEvent.OrderEventEnum.INIT_SUCCESS, new OrderInitTransition()) 
//構建拓撲表
.installTopology();
複製代碼
  • 執行過程代碼
//將自定義request參數傳入狀態機,根據傳入status爲默認狀態返回一個狀態機。
  //若是拓撲表爲構建會從新執行一遍構建過程
  orderStateMachine = OrderStateMachine.getStateMachine(request, OrderStatusEnum.getById(request.getOrderStatus()));
  
  //狀態轉移過程 返回次態
  orderStateMachine.doTransition(orderEvent.getOrderEvent(), orderEvent)
  
  //具體doTranstion方法
  private STATE doTransition (OPERAND operand, STATE oldState, EVENTTYPE eventType, EVENT event) throws InvalidStateTransitionException {
      //根據訂單狀態找到以前構建的map
      Map<EVENTTYPE, Transition<OPERAND, STATE, EVENTTYPE, EVENT>> transitionMap
        = stateMachineTable.get(oldState);
      if (transitionMap != null) {
      //根據事件找到具體動做
        Transition<OPERAND, STATE, EVENTTYPE, EVENT> transition
            = transitionMap.get(eventType);
        if (transition != null) {
        	//執行動做
          return transition.doTransition(operand, oldState, event, eventType);
        }
      }
      throw new InvalidStateTransitionException(oldState, eventType);
    }
  
複製代碼
  • 主要核心代碼大概就是上面這些,筆者主要是拋棄了多弧過渡,訂單系統中能夠優化單弧過渡執行方法時直接將次態帶入自定義的transition 這樣能夠將同類型的多個transition 合併
相關文章
相關標籤/搜索