java設計模式之:責任鏈模式(企業級案例)

java設計模式一共有23種,其中主要分爲三大類:

1:創建型模式

工廠方法模式、抽象工廠模式、單例模式、創建者模式、原型模式。

2:結構型模式

適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。

3:行爲模式

策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模狀態模式、訪問者模式、中介者模式、解釋器模式。

今天我們主要講解行爲模式中的責任鏈模式:
 

白話講責任鏈模式

什麼是責任鏈模式:責任鏈模式,故名思意就是一個鎖鏈一般,前一個扣着下一個,組成的一個鏈條。請求端只需要發起請求,但是不需要知道具體的實現。目的是爲了解決請求端與實現端的解耦。

責任鏈一般由多個實現組成,當收到請求的時候處於責任鏈第一個實現會進行判斷是否可以處理,不可以則傳遞給下一個處理,如此按照順序執行。當然下一個是誰也是我們自己在定義的時候指定的,實現的執行順序是我們在創建的時候指定的。

責任鏈的好處:

1.請求與實現解耦,實現之間管理維護方便。

2.具體實現不需要知道責任鏈的內部結構,只需要維護自己實現,降低了維護難度

3.可以修改內部鏈的執行順序

4.新增實現簡單方便。

責任鏈的弊端:

1.因爲只關心自己內部實現,不關心鏈內部結構,開發調試會比較麻煩。因爲你壓根就不清楚他調用的會是哪一個實現。

2.增加系統的資源消耗。因爲鏈式調用,可能會進行很多次判斷,因爲每個實現都會判斷是否能夠處理該請求,不能處理則調用下一個,增加了系統開銷

3.不能保證請求被消化,正是因爲其特殊的特性,在處理之前會判斷是否能夠處理,如果每一個鏈都不能處理,那麼該請求無法被消化。

責任鏈的應用場景:java中的filter過濾器,各種權限控制。

圖解:

責任鏈模式

 

通過上圖我們簡單分析一個責任鏈的原理,以及執行流程。爲什麼能解除調用者以及實現之間的耦合呢?

上訴流程圖有兩個角色非常重要,

第一個:我們的父類抽象方法,這裏就暫且叫做abstractHandle把,我們的abstractHandle的作用就是提供抽象功能接口,以及提供設置下一個實現鏈的方法。

第二個:我們的實現工廠,暫且就叫做chainFactory,我們的chainFactory是用於管理我們的責任鏈的,他負責創建以及管理每個責任鏈的調用順序,也就是執行順序以及創建是在這裏完成。

除了上訴的兩個角色就是我們剩下的具體的實現了,每個實現只負責自己需要實現的部分,對於不滿足要求的則調用下個實現。

上面簡單的將我們責任鏈中的每個角色都簡單的介紹了一下。那麼接下來我們就按照一個簡單的java例子並結合我們的上圖進行講解一下責任鏈模式。還可以參考我們java中的filter。

 

案例介紹:我們使用責任鏈設計一個簡單的java公司請假批准程序,其中如果請假的天數在自己的可以受理範圍內,則自己處理,如果不能處理則不出來,交給下一個實現,具體是那個處理,自己不用關心。

主要角色:

1.部門主管,受理請假時長爲三天之內的請假請求。

2.人事經理,受理請假時長爲四天到八天之內的請假請求。

3.項目經理,對大於八天的請假時長作處理,如果不大於12天,則允許,否則拒絕。

順帶一提。如果是傳統處理方案的話,我們需要對請假時長作判斷,用if elseif 或者switch進行條件判斷調用不同的方法,但是使用責任鏈模式則可以避免多重if,以及switch。(只需要記住,責任鏈可以解決多重if以及switch)

那好下面我們開始代碼編寫:

1.首先我們先定義我們的abstractHandle類:

/**
 * 審覈類
 *
 * @author 李昆城
 */
@Data
@SuppressWarnings("unused")
@AllArgsConstructor
@NoArgsConstructor
public abstract class BaseAudit {


    /**
     * 請假處理對象
     */
    protected BaseAudit audit;


    /**
     * 請假處理
     */
    abstract boolean vacateAudit(int number) throws Exception;

    /**
     * 開始下一個處理
     */
    boolean nextAudit(int number) throws Exception {
        return audit.vacateAudit(number);
    }

}

我們的abstractHandle只有兩個方法以及一個成員屬性,分別是用作處理請假,以及調用下一個實現處理請假和保存下一個實現的成員屬性。

2.有了成員屬性我們開始創建具體的實現:

部門主管


/**
 * 部門主管審覈
 *
 * @author 李昆城
 */
public class DepartmentManagerAudit extends BaseAudit {


    @Override
    public boolean vacateAudit(int number) throws Exception {
        if (number > 3) {
            return nextAudit(number);
        }
        System.out.println("\t\n部門主管開始處理請假。");
        System.out.println("我是部門主管,我同意了");
        return true;
    }
}

人事經理


/**
 * 人事主管審覈
 *
 * @author 李昆城
 **/
public class PersonnelManagerAudit extends BaseAudit {


    @Override
    public boolean vacateAudit(int number) throws Exception {
        if (number > 8) {
            return nextAudit(number);
        }
        System.out.println("\t\n人事主管開始處理請假。");
        System.out.println("我是人事主管,我同意了");
        return true;
    }
}

項目經理

/**
 * 項目經理
 *
 * @author 李昆城
 **/
public class ProjectManagerAudit extends BaseAudit {

    @Override
    public boolean vacateAudit(int number) throws Exception {
        System.out.println("\t\n項目經理開始處理請假。");
        if (number > 12) {
            throw new IllegalAccessException("項目緊張,請假天數不能大於3天,不予批准。");
        }
        System.out.println("我是項目經理,我同意了。");
        return true;
    }
}

3.有了我們具體的實現,那麼我們需要一個工廠,爲我們創建,並且管理我們的責任鏈。

/**
 * 審覈工廠
 *
 * @author Administrator
 **/
public class AuditFactory {

    /**
     * 得到第一個審覈人
     *
     * @return 審覈
     */
    public DepartmentManagerAudit getBaseAudit() {
        //部門主管
        DepartmentManagerAudit departmentManagerAudit = new DepartmentManagerAudit();
        //人事經理
        PersonnelManagerAudit personnelManagerAudit = new PersonnelManagerAudit();
        departmentManagerAudit.setAudit(personnelManagerAudit);

        //項目經理
        ProjectManagerAudit projectManagerAudit = new ProjectManagerAudit();
        personnelManagerAudit.setAudit(projectManagerAudit);
        return departmentManagerAudit;
    }
}

我們的工廠可以很清晰的看到,我們創建了三個實現,分別是,部門主管、人事經理、項目經理,分別對應DepartmentManagerAudit,PersonnelManagerAudit,ProjectManagerAudit,並且指定了責任鏈執行的順序,分別是,部門主管,人事經理,項目經理。

4.ok下面我們設計我們的請求調用者

/**
 * 啓動類
 *
 * @author 李昆城
 */
public class App {


    public static void main(String[] args) {
        AuditFactory auditFactory = new AuditFactory();
        DepartmentManagerAudit baseAudit = auditFactory.getBaseAudit();
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < 10; i++) {
            System.out.print("\t\n你好,請輸入你的請假天數:");
            if (!scanner.hasNextInt()) {
                System.out.println("請輸入合法的請假天數");
                continue;
            }
            int number = scanner.nextInt();
            System.out.println("請假申請已經提交。");
            try {
                if(baseAudit.vacateAudit(number)){
                    System.out.println("恭喜你,請假成功!");
                };

            } catch (Exception e) {
                System.out.println("請假失敗:" + e.getMessage());
                continue;
            }
        }
    }
}

ok,可以看到我們通過工廠獲取到我們的抽象審覈請假的實例,然後輸入請假請求,輸入天數,調用我們的審覈方法進行判斷並且確定具體的處理人,但是在整個過程中調用者什麼都不知道,也不知道具體實現,只知道自己提交了請假申請。這樣就很好的解決了調用者和申請者之間的耦合,且每個角色(部門主管,人事主管,項目經理)等都只需要維護自己的實現方式,也便於維護,同樣缺點就是如果發生問題,不好流程最終,相當於工廠是一個黑匣子,吧我們的具體實現完全給拒絕在外面

代碼地址:https://gitee.com/happy_bug/designMode/tree/master/src/main/java/com/likuncheng/responsibilitychain

 

另外下面我會帶來企業級的真實案例,這裏只能貼出關鍵代碼。

首先講解一下需求:需求就是一個多角色多權限登錄的一個功能,

就是多重角色的登錄,登陸用戶只需要告訴我你是什麼角色,以及關鍵登錄信息即可,調用方完全不知道具體每個角色的實現。

這裏貼出部門關鍵代碼:https://gitee.com/happy_bug/designMode/tree/master/src/main/java/com/likuncheng/responsibilitychain/enterprisecase

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章