採購申請的處理流程 --- 責任鏈模式

anly_jun發表於2017-02-22

前情提要

上集講到小光梳理了公司的組織架構, 利用組合模式建立起了一個可擴充套件變化的多層的組織架構體系. 更清晰地明確了公司各個層級, 各個部門的職責. 大家明確職責, 通力合作, 讓"小光熱乾麵"這個招牌越做越好.

然而, 小光畢竟是經歷過幾任大企業的人啊, 弄好組織結構只是小光企業管理的第一步, 接下來小光準備要梳理下工作流了.

所有示例原始碼已經上傳到Github, 戳這裡

比如採購的審批流程

剛開始, 小光只有光谷一個店的時候, 很多時候採購某些東西也就沒有什麼流程, 大家一商量, 小光拍板, 就派人去採購了. 然而, 現在發展到好幾個分店了, 小光肯定不能做到事事過問了, 故而會有一些放權, 但是某些情況(大件的採購)小光肯定還是想要到自己這裡審批的.

想到這些, 小光想著第一個需要建立的就是這個採購審批流程了.

做一個採購審批系統

先分析問題

那麼該怎麼做呢?
正所謂問對了問題, 也就解決了一半. 小光一貫的做法, 是先想清楚問題是什麼, 然後再針對性的出解決方案.

那麼, 再回頭看看, 問題具體是什麼呢?

  1. 一個採購申請的審批流程系統
  2. 不同物件採購的審批流程並不是一樣的(有的可能會到小光那兒, 有的沒有必要)
  3. 同一個審批流程也可能會有變化(如上期組織結構所言, 公司組織結構會不斷調整, 肯定會影響到採購審批層級的變化).

相應的解決點

問清楚了問題, 小光針對性的想了下方案的特性:

  1. 首先肯定是一個流程化的東東, 也就是說類似流水線的處理審批單. 例如採購員提出採購單, 採購部經理審批蓋章, 到總經理審批...

    採購申請的處理流程 --- 責任鏈模式

  2. 不只是一條這樣的流水線, 不同型別審批單的流水線不一致, 故而應該是有幾條流水線.

  3. 因為流水線上的操作員(由於公司層級的調整, 部門變化)會變化, 故而流水線的每個節點最好是可定製的.

解決之道

瞭解了問題及其對應的特性, 小光開始了自己的採購審批系統設計.

首先, 對於第一個特性, 小光心想, 這很簡單, 實際上就是一個指向性的呼叫嘛, A呼叫B, B再呼叫C...如此這般即可.

當然, 小光物件導向的程式設計思想已經深入腦髓, 他將採購員, 採購經理, 總經理都物件化了. 另外, 採購經理和總經理以及小光, 都視為是可以處理採購申請的人, 故而抽象出了一個RequestHandler:

RequestHandler(採購申請處理人)

public abstract class RequestHandler {

    // 上一級的處理人員
    private RequestHandler mNext;

    public RequestHandler(RequestHandler next) {
        this.mNext = next;
    }

    /**
     * 處理採購需求
     * @param req
     */
    public void handleRequest(Request req) {
        printHandling(req);
        if (mNext != null) {
            mNext.handleRequest(req);
        }
    }

    protected void printHandling(Request req) {
        System.out.println(this.toString() + "審批了:" + req);
    }

    @Override
    public abstract String toString();
}複製程式碼

採購經理:

public class PurchasingManager extends RequestHandler {

    /**
     * 構造時, 傳入下一個處理人
     * @param next 下一個處理人
     */
    public PurchasingManager(RequestHandler next) {
        super(next);
    }

    @Override
    public String toString() {
        return "採購部經理";
    }
}複製程式碼

總經理和小光的實現與採購經理類似, 在此略過, 大家可以參看github上的原始碼.

為了滿足問題的第2點:

不同物件採購的審批流程並不是一樣的(有的可能會到小光那兒, 有的沒有必要)

還需要有一些定製的流程:

public class RequestFlow {

    public static final int TYPE_SMALL_REQUEST = 1;
    public static final int TYPE_NORMAL_REQUEST = 2;
    public static final int TYPE_BIG_REQUEST = 3;

    public static RequestHandler getRequestChain(int type) {
        switch (type) {
            // 小物件, 只需採購經理審批
            case TYPE_SMALL_REQUEST:
                return new PurchasingManager(null);

            // 一般物件, 需要總經理審批
            case TYPE_NORMAL_REQUEST:
                return new PurchasingManager(new GeneralManager(null));

            // 大件物品, 需要小光審批
            case TYPE_BIG_REQUEST:
            default:
                return  new PurchasingManager(new GeneralManager(new XiaoGuang(null)));
        }
    }
}複製程式碼

讓我們看看採購員的請求方式:

// 採購員
public class Buyer {

    public static void main(String[] args) {

        // 小需求
        Request smallRequest = new Request("10箱飲料");
        RequestFlow.getRequestChain(RequestFlow.TYPE_SMALL_REQUEST).handleRequest(smallRequest);

        // 一般需求
        Request normalRequest = new Request("10套桌椅");
        RequestFlow.getRequestChain(RequestFlow.TYPE_NORMAL_REQUEST).handleRequest(normalRequest);

        // 大需求
        Request bigRequest = new Request("一套同步電子顯示大屏");
        RequestFlow.getRequestChain(RequestFlow.TYPE_BIG_REQUEST).handleRequest(bigRequest);

    }
}複製程式碼

// 小需求 輸出:
採購經理審批了:10箱飲料採購申請

// 一般需求  輸出:
採購經理審批了:10套桌椅採購申請
總經理審批了:10套桌椅採購申請

// 大需求 輸出:
採購經理審批了:一套同步電子顯示大屏採購申請
總經理審批了:一套同步電子顯示大屏採購申請
小光審批了:一套同步電子顯示大屏採購申請複製程式碼

可以看到, 小光目前設計的這套系統是可以業務審批流程的需求的. 我們這裡RequestFlow實際上採用簡單工廠的模式, 適用於流程數比較少的情況. 如果考慮到後續的組織架構的變化影響什麼的, 這塊是值得重構一下的.


另外一個可優化的是, 我們實際上並不需要這麼多的流水線, 可能只需要定製最長的那條, 然後在每個節點上根據傳過來的審批請求來決定是否在當前節點就消化掉, 還是說還要傳給上一級處理. 大家可以自己嘗試修改下~~

故事之後

故事情節相對簡單, 然而確確實實這個就是責任鏈模式的一個應用. 照例, 我們上UML類圖, 看下各個部分的關係(為了清晰展示鏈的關係, 類圖中國捨棄RequestFlow這個工廠):

採購申請的處理流程 --- 責任鏈模式

責任鏈模式
很多物件由每一個物件對其下家的引用(mNext)而連線起來形成一條鏈. 請求在這個鏈上傳遞, 直到鏈上的某一個物件決定處理此請求.
行為解耦的一種模式, 呼叫者並不確切知道也無需知道行為的執行者是誰.

擴充套件閱讀一

開發Android的同學可能都用過大名鼎鼎的OkHttp了, OkHttp的核心其實就是其攔截器鏈(interceptor chain)的實現. 個人認為其最巧妙的也是這個攔截器鏈的實現了, 完美契合.

讓我們先簡單縷下OkHttp的request流程:

採購申請的處理流程 --- 責任鏈模式

簡單分析CacheInterceptor(OkHttp的快取實現):

  @Override public Response intercept(Chain chain) throws IOException {
    ...

    // 取快取的Response
    Response cacheResponse = strategy.cacheResponse;

    // 如果快取滿足要求, 直接返回. 相當於採購經理能夠審批該採購請求, 無需上報給總經理.
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }

    // 如果不能, 則交給鏈路的下一個責任人來處理.
    try {
      networkResponse = chain.proceed(networkRequest);
    } finally {
      ...
    }

    // 對一個鏈點返回的response做處理, 看是否要快取起來.
    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    if (HttpHeaders.hasBody(response)) {
      CacheRequest cacheRequest = maybeCache(response, networkResponse.request(), cache);
      response = cacheWritingResponse(cacheRequest, response);
    }

    return response;
  }複製程式碼

大家可以看到, 只是一個典型的責任鏈模式的運用.
牛逼的是, OkHttp中的攔截器(interceptor)不僅僅是單向的一個鏈點, 而是一個雙向的迴路. 每個鏈路節點, 在request的過程中會做一次攔截處理, 諸如是否直接返回快取, 加上統一的UserAgent等; 在response回來之後會再做一次攔截處理, 例如快取, 根據response header做相關處理等. 如下:

採購申請的處理流程 --- 責任鏈模式
okhttp

強烈建議Android開發的同學可以深入研究下OkHttp的interceptor鏈這塊的處理, 肯定是受益匪淺~


搭建後初步的審批體系, 小光又開始暢想未來了~~


最近工作真的是太忙了, 本系列延期了又延期, 抱歉.


借自己的廣告位, 廣告一波
大量高階Android坑位求自薦, 求推薦.
關鍵詞:
alibaba.com這個App的開發
座標杭州
3年及以上Android平臺開發經驗
簡歷請發至anly_jun@163.com, 謝謝.


相關文章