1. 程式人生 > >基於狀態模式的簡單工作流實現

基於狀態模式的簡單工作流實現

  • 工作流技術(Workflow) 是工作流程的計算模型,即將工作流程中的工作如何前後組織在一起的邏輯和規則在計算機中以恰當的模型進行表示,並對其實施計算。工作流要解決的主要問題是:為實現某個業務目標,在多個參與者之間,利用計算機,按某種預定規則自動傳遞文件、資訊或是任務。
  • 簡單地說,工作流就是對工作流程及其各操作步驟之間業務規則的抽象、概括、描述。比如在企業OA系統中我們常用的請假流程報銷流程等等各種審批流程。
  • 對於簡單的業務而言,流程控制不會太複雜,可以使用狀態模式(State Pattern)來輔助進行流程控制。因為大部分的流程都是狀態驅動的!
      假設有這樣的“請假流程”的場景:某位程式設計師提出請假申請,先由專案經理審批,如果專案經理不同意,則流程結束;如果專案經理同意,再看請假天數是否超過3天,如果在專案經理審批許可權內(3天),則審批流程也直接結束,否則交給部門經理;部門經理稽核後無論是否同意,流程都直接結束。流程圖如下:
    在這裡插入圖片描述

    在實際開發中,如果不考慮使用工作流框架,自己實現整個流程的過程簡單描述如下:
    1)UI操作:請假人提交請假單,提出申請
    2)後臺處理:儲存請假單資料到資料庫,為專案經理新建一個工作,把工作資訊儲存到資料庫
    3)UI操作:專案經理登入系統,獲取自己的工作列表
    4)後臺處理:從資料庫中查詢相應的工作列表
    5)UI操作:專案經理完成稽核工作,提交儲存
    6)後臺處理:處理專案經理的稽核業務,儲存稽核資訊到資料庫。同時判斷後續的工作,如果是需要人員參與的,則為參與工作的下一個人員建立工作,把工作資訊儲存到資料庫
    7)UI操作:部門經理登入系統,獲取自己的工作列表,重複步驟3
    8)後臺處理:從資料庫中查詢相應的工作列表,重複步驟4
    9)UI操作:部門經理完成稽核工作,提交儲存,重複步驟5
    10)後臺處理:類似步驟6

使用狀態模式實現工作流思路:

  • 仔細分析上面的流程圖和請假流程的執行過程,把請假單在流程中的各個狀態分析出來,我們發現,整個流程完全可以看成是狀態驅動的!
  • 在上述流程中,“請假單”大致有如下狀態:等待專案經理稽核、等待部門經理稽核、稽核結束。
  • 既然可以把流程看做是狀態驅動的,那麼就可以自然地使用狀態模式,每當相應的工作人員完成工作,請求流程響應的時候,流程處理物件會根據當前所處的狀態,把流程處理委託給相應的狀態物件去處理。

為了簡單起見,不採用資料庫儲存資料,直接通過控制檯接收資料,模擬一個請假流程,demo如下:

  • 狀態處理機
package com.zpc.test.statepattern;

/**
 * 狀態處理機,相當於狀態模式中的Context
 */
public class StateMachine {
    /**
     * 持有一個狀態物件
     */
    private State state;

    /**
     * 流程處理需要的業務資料物件
     */
    private Object businessObj;

    public void doWork(){
        //轉調相應的狀態物件真正完成功能處理
        this.state.doWork(this);
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public Object getBusinessObj() {
        return businessObj;
    }

    public void setBusinessObj(Object businessObj) {
        this.businessObj = businessObj;
    }
}

  • 狀態介面
package com.zpc.test.statepattern;

/**
 * 狀態介面
 */
public interface State {
    /**
     * 執行狀態對應的處理功能
     *
     * @param context 上下文例項
     */
    void doWork(StateMachine context);
}

  • 業務模型
package com.zpc.test.statepattern;

/**
 * 請假單的業務模型
 */
public class LeaveRequestModel {
    /**
     * 請假人
     */
    private String user;
    /**
     * 請假開始日期
     */
    private String dateBegin;
    /**
     * 請假天數
     */
    private Integer leaveDays;
    /**
     * 稽核結果
     */
    private String result;

    public String getUser() {
        return user;
    }

    public void setUser(String user) {
        this.user = user;
    }

    public String getDateBegin() {
        return dateBegin;
    }

    public void setDateBegin(String dateBegin) {
        this.dateBegin = dateBegin;
    }

    public Integer getLeaveDays() {
        return leaveDays;
    }

    public void setLeaveDays(Integer leaveDays) {
        this.leaveDays = leaveDays;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }
}

  • 業務狀態機
package com.zpc.test.statepattern;

/**
 * 雖然這裡並不需要擴充套件功能,但是還是繼承一下狀態機,表示可以新增自己的處理
 */
public class LeaveRequestContext extends StateMachine {
}

  • 業務狀態
package com.zpc.test.statepattern;
/**
 * 雖然這裡並不需要擴充套件功能,但是還是繼承一下狀態,表示可以新增自己的處理
 */
public interface LeaveRequestState extends State {
}

  • 專案經理稽核狀態類
package com.zpc.test.statepattern;

import java.util.Scanner;

public class ProjectManagerState implements LeaveRequestState {
    @Override
    public void doWork(StateMachine context) {
        //先提取業務物件
        LeaveRequestModel businessObj = (LeaveRequestModel) context.getBusinessObj();
        System.out.println("專案經理稽核中。。。");
        //模擬使用者介面,從控制檯讀取資料
        System.out.println(businessObj.getUser() + "申請從" + businessObj.getDateBegin() + "開始請假" + businessObj.getLeaveDays() + "天,請專案經理稽核(1同意,2不同意):");
        Scanner scanner = new Scanner(System.in);
        if (scanner.hasNext()) {
            int a = scanner.nextInt();
            String res = "不同意";
            if (a == 1) {
                res = "同意";
            }
            businessObj.setResult("專案經理稽核結果:" + res);
            //根據選擇的結果和條件選擇下一步
            if (a == 1) {
                if (businessObj.getLeaveDays() > 3) {
                    //3天以上的假專案經理同意了則交由部門經理稽核
                    context.setState(new DepManagerState());
                    context.doWork();
                } else {
                    //3天以內的假專案經理直接做主,就不用交給部門經理了,轉向稽核結束狀態
                    context.setState(new AuditOverState());
                    context.doWork();
                }
            } else {
                //如果專案經理不同意,就不用交給部門經理了,轉向稽核結束狀態
                context.setState(new AuditOverState());
                context.doWork();
            }
        }
    }
}

  • 部門經理稽核狀態類
package com.zpc.test.statepattern;

import java.util.Scanner;

public class DepManagerState implements LeaveRequestState {
    @Override
    public void doWork(StateMachine context) {
        //先提取業務物件
        LeaveRequestModel businessObj = (LeaveRequestModel) context.getBusinessObj();
        System.out.println("部門經理稽核中。。。");
        //模擬使用者介面,從控制檯讀取資料
        System.out.println(businessObj.getUser() + "申請從" + businessObj.getDateBegin() + "開始請假" + businessObj.getLeaveDays() + "天,請部門經理稽核(1同意,2不同意):");
        Scanner scanner = new Scanner(System.in);
        if (scanner.hasNext()) {
            int a = scanner.nextInt();
            String res = "不同意";
            if (a == 1) {
                res = "同意";
            }
            businessObj.setResult("部門經理稽核結果:" + res);
            //部門經理稽核後,轉向稽核結束狀態
            context.setState(new AuditOverState());
            context.doWork();
        }
    }
}
  • 稽核結束狀態類
package com.zpc.test.statepattern;

public class AuditOverState implements LeaveRequestState {
    @Override
    public void doWork(StateMachine context) {
        LeaveRequestModel businessObj = (LeaveRequestModel) context.getBusinessObj();
        System.out.println(businessObj.getUser()+",請假流程結束,結果是:"+businessObj.getResult());
    }
}

  • 執行測試
package com.zpc.test.statepattern;

/**
 * 測試類
 */
public class Client {
    public static void main(String[] args) {
        //建立業務物件,設定資料
        LeaveRequestModel model=new LeaveRequestModel();
        model.setUser("鳥鵬");
        model.setDateBegin("20180930");
        //model.setLeaveDays(1);
        model.setLeaveDays(4);

        LeaveRequestContext context=new LeaveRequestContext();
        context.setBusinessObj(model);
        //配置上下文的初始狀態,以後就隨流程而動態變化(狀態驅動)
        context.setState(new ProjectManagerState());
        context.doWork();
    }
}

手動在控制檯輸入1(同意),2(不同意)試試看!

相關推薦

基於狀態模式簡單工作實現

工作流技術(Workflow) 是工作流程的計算模型,即將工作流程中的工作如何前後組織在一起的邏輯和規則在計算機中以恰當的模型進行表示,並對其實施計算。工作流要解決的主要問題是:為實現某個業務目標,在多個參與者之間,利用計算機,按某種預定規則自動傳遞文件、資訊

淺談簡單工作設計——責任鏈模式配合策略與命令模式實現

本文以專案中的一個工作流模組,演示責任鏈模式、策略模式、命令模式的組合實現! 流程簡介 最近在做的一個專案,涉及到的是一個流程性質的需求。關於工程機械行業的服務流程:服務任務流程和備件發運流程。 專案之初,需求不是很清晰,算是演化模型吧。先出一個簡單版本,然後根據使用者的

用activiti 工作 實現簡單的請假 附帶原始碼 / SSM整合Activiti工作(不錯,可以看看)

http://blog.csdn.net/lvsehuoyan/article/details/38408649 新建一個Maven專案 專案結構 pom.xml <projectxmlns="http://maven.apache.org/POM/4.0.0"

用activiti 工作 實現簡單的請假 附帶原始碼

新建一個Maven專案 專案結構 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

CentOS7基於FPM模式編譯LAMP,實現多虛擬主機應用wordpress

lamp、wordpress該實驗需要的軟件環境:apr-1.6.2.tar.gz httpd-2.4.27.tar.bz2 php-7.1.10.tar.xzapr-util-1.6.0.tar.gz mariadb-10.2.8-linux-x86_64.tar

基於Petri網的工作如何執行

A transition may only fire if it is enabled. This occurs when there is at least one token at each of its input places. The transitions are then, as it w

力軟敏捷開發框架工作實現技術

工作流、框架、代碼生成器、二次開發 工作流管理聯盟(WFMC)提出了一個工作流參考模型,約定了工作流系統的體系結構、應用接口及特性,主要目的是為了實現工作流技術的標準化和開放性。下面簡要介紹系統中的各個部分,並對參考模型中的五類接口進行描述。 1. 工作流管

Git 簡單工作,幫你快速使用 Git

安裝 Installing on Mac 通過 Homerew 安裝 brew install git 其它平臺安裝可以參考:Installing Git 建立新倉庫 建立新資料夾,進入,然後執行: git init 檢出倉庫 // 從本地 git c

WCF4.0進階系列 使用工作實現服務

轉載原地址:https://www.cnblogs.com/zzw1986/p/4709842.html 【前言】 企業使用WCF服務的一個主要原因是通過包裝現有的元件和程式構建面向服務的應用,這些應用通過不僅簡單而且適應力很強地方式重用。這種策略為企業帶來了非常大的靈活性,因為它可以簡單地

js簡單瀑布實現

什麼是瀑布流 瀑布流其實就是一種佈局方式,比如說有很多模組,這些模組大小不一,怎樣才能把這些模組相對漂亮的排列到一起?瀑布流就可以很好地解決這個問題。首先把這些模組的寬(高)都設定一樣,然後讓他們像瀑布一樣從上到下依次排列。如果還不清楚的話,強烈建議大家去看一

設計模式-簡單工廠-C++實現

簡單工廠方法:定義一個建立物件的介面,讓子類決定例項化那一個類。框架定義了和維護物件之間的關係,同時物件的產生也是由框架來負責。 場景: 1.當一個類不知道他所必須建立的物件的類的時候; 2.當一個類希望有它的子類指定他所建立的物件的時候。 #include <stdio.

docker ppt: 桂陽:通過工作實現Docker在CoreOS自動化部署

Automated Deploy Docker Containers on CoreOS 桂陽

基於jquery的簡單分頁實現

先上圖: 之前在做表格外掛想把分頁整合進去,原本去網站找一個現成的整合進去,發現有些太簡單或者很複雜,達不到自己的要求,自己想還是自己整一個,順便了解一下其中的原理。 分頁樣式是基於boosta

固定列寬的簡單瀑布實現

在看JavaScript實戰中看到瀑布流,決定記錄下程式碼,以備不時之需。 首先寫一個HTML程式碼 <!DOCTYPE html> <html> <head> <title>瀑布流</title> <link

JavaWeb,不使用框架下的MVC模式簡單登陸模組實現

專案結構圖 1. 前期準備 本專案使用的jdk版本是:jdk1.8.0_181 本專案使用的tomcat版本是:apache-tomcat-7.0.90 本專案使用的mysql資料庫版本是:mysql8.0 本專案使用的資料庫驅動是:my

Activiti工作實現檢視流程圖圖片並在當前流程上新增紅圈

為什麼要用Activiti工作流以及Acitiviti工作流的基礎用法就不多說了,廢話不多說,直接上程式碼(呼叫該方法,頁面使用img標籤即可)package com.supermap.zzsubcorp.iPark.assetsMetaDataEngine.activiti

工作實現自定義表單

定義概述:一個已經做好的表單需要繫結到節點上。 自定義表單工作模式:流程控制按鈕區域是ccflow來完成,表單區域是放在控制區域下面的框架裡。 注意:藍色邊框一下是一個框架,框架裡面的介面是一個url,這個就是自定義表單。 應用背景:這種型別是解決我自己已經有了一個成

工作實現分合流(多人、多部門分工處理)的介紹

分合流:顧名思義,想長江一樣,有主流河流和分支河流,有起點,有終點。 適用範圍:多人、多角色、多崗位、多部門等相互獨立審批工作、處理工作,同時又可在某個步驟中檢視工作的彙總、或者過程、或者處理結果等

在MVC程式中,使用泛型倉儲模式工作單元實現增刪查改

在這片文章中,我將自己動手為所有的實體:寫一個泛型倉儲類,還有一個工作單元。 工作單元的職責就是:為每一個實體,建立倉儲例項。倉儲(倉庫)的職責:增刪查改的功能實現。 我們將會在控制器中,建立工作單元類(UnitOfWork)的例項,然後根據實體,建立倉儲例項,再就是

一個輕量級的基於RateLimiter的分散式限實現

上篇文章([限流演算法與Guava RateLimiter解析](http://blog.jboost.cn/ratelimiter.html))對常用的限流演算法及Google Guava基於令牌桶演算法的實現RateLimiter進行了介紹。RateLimiter通過執行緒鎖控制同步,只適用於單機應用,在