天天看點

設計模式之責任鍊模式(附實戰代碼)

請求的鍊式處理——職責鍊模式

if(條件1) {
    此時要調用balabalabala類去處理具體的邏輯

} else if (條件2){
    此時要調用dadadadadada類去處理具體的邏輯

} else if (條件3) {
    此時要調用aaaaaaaaaaaa類去處理具體的邏輯
}
           

好這段代碼是不是很熟悉呢,對于一些多條件的邏輯處理這應該是很普遍的開發方法了吧,那麼會有什麼問題呢?

1、耦合度太高,如果條件改變,或者新增條件,就要修改代碼,違反了“開閉原則”;

2、各個條件的邏輯處理類,都集中在一個類中,違反了“單一職責原則”,測試和維護難度大。

。。。。。。

好,下面我們進入正題

先來張偷來的圖,顯着高大上一些,哈哈哈哈

設計模式之責任鍊模式(附實戰代碼)

在職責鍊模式結構圖中包含如下幾個角色:

● Handler(抽象處理者):它定義了一個處理請求的接口,一般設計為抽象類,由于不同的具體處理者處理請求的方式不同,是以在其中定義了抽象請求處理方法。因為每一個處理者的下家還是一個處理者,是以在抽象處理者中定義了一個抽象處理者類型的對象(如結構圖中的successor),作為其對下家的引用。通過該引用,處理者可以連成一條鍊。

● ConcreteHandler(具體處理者):它是抽象處理者的子類,可以處理使用者請求,在具體處理者類中實作了抽象處理者中定義的抽象請求處理方法,在處理請求之前需要進行判斷,看是否有相應的處理權限,如果可以處理請求就處理它,否則将請求轉發給後繼者;在具體處理者中可以通路鍊中下一個對象,以便請求的轉發。

在職責鍊模式裡,很多對象由每一個對象對其下家的引用而連接配接起來形成一條鍊。請求在這個鍊上傳遞,直到鍊上的某一個對象決定處理此請求。發出這個請求的用戶端并不知道鍊上的哪一個對象最終處理這個請求,這使得系統可以在不影響用戶端的情況下動态地重新組織鍊和配置設定責任。

職責鍊模式的核心在于抽象處理者類的設計,抽象處理者的典型代碼如下所示:

public abstract class ChainOfDutyService {

    protected ChainOfDutyService handlerService;//後繼者

    public void setHandlerService(ChainOfDutyService handlerService) { //設定後繼者
        this.handlerService = handlerService;
    }

    public abstract void processRequest(int count);//處理邏輯的方法
}
           

具體處理者類的典型代碼如下:

public class HandlerOneService extends ChainOfDutyService {
    @Override
    public void processRequest(int count) {
        if (count < 100) {
            System.out.println("HandlerOneService處理,count: " + count);
        } else {
            this.handlerService.processRequest(count);
        }
    }
}
           
public class HandlerTwoService extends ChainOfDutyService {
    @Override
    public void processRequest(int count) {
        if (count >= 100 && count < 200) {
            System.out.println("HandlerTwoService處理, count: " + count);
        } else {
//            this.handlerService.processRequest(count);
        }
    }
}
           

職責鍊模式并不建立職責鍊,職責鍊的建立工作必須由系統的其他部分來完成,一般是在使用該職責鍊的用戶端中建立職責鍊。職責鍊模式降低了請求的發送端和接收端之間的耦合,使多個對象都有機會處理這個請求。

用戶端的典型代碼如下:

public class ChainOfDutyController {

    public static void main(String[] args) {
        int count = 150;
        //1、建立具體處理者類(該處可交由Spring管理,省去new建立對象,比較low的方式)
        HandlerOneService handlerOneService = new HandlerOneService();
        HandlerTwoService handlerTwoService = new HandlerTwoService();
        //2、設定責任鍊
        handlerOneService.setHandlerService(handlerTwoService);
        //3、由首個設定責任鍊的具體處理類開始調用
        handlerOneService.processRequest(count);
    }
}
           

好啦,如果沒看懂就去手動敲一遍吧,很好了解對吧,但是有些注意事項我還是要羅嗦兩句,畢竟到了總結發言的時刻

1、用戶端也就是控制類在設定後繼者的時候不可形成閉環,如果形成閉環,同時條件都不滿足,會循環調用至記憶體溢出
2、用戶端也就是控制類在設定後繼者的時候最後一個後繼者沒有else,否則不滿足條件是進入else因為無後繼者會報錯空指針
3、調用處理方法是,要用首個設定後繼者的實作類開始調用
           

職責鍊模式總結

職責鍊模式通過建立一條鍊來組織請求的處理者,請求将沿着鍊進行傳遞,請求發送者無須知道請求在何時、何處以及如何被處理,實作了請求發送者與處理者的解耦。在軟體開發中,如果遇到有多個對象可以處理同一請求時可以應用職責鍊模式,例如在Web應用開發中建立一個過濾器(Filter)鍊來對請求資料進行過濾,在工作流系統中實作公文的分級審批等等,使用職責鍊模式可以較好地解決此類問題。

1.主要優點

職責鍊模式的主要優點如下:

(1) 職責鍊模式使得一個對象無須知道是其他哪一個對象處理其請求,對象僅需知道該請求會被處理即可,接收者和發送者都沒有對方的明确資訊,且鍊中的對象不需要知道鍊的結構,由用戶端負責鍊的建立,降低了系統的耦合度。

(2) 請求處理對象僅需維持一個指向其後繼者的引用,而不需要維持它對所有的候選處理者的引用,可簡化對象的互相連接配接。

(3) 在給對象分派職責時,職責鍊可以給我們更多的靈活性,可以通過在運作時對該鍊進行動态的增加或修改來增加或改變處理一個請求的職責。

(4) 在系統中增加一個新的具體請求處理者時無須修改原有系統的代碼,隻需要在用戶端重建立鍊即可,從這一點來看是符合“開閉原則”的。

2.主要缺點

職責鍊模式的主要缺點如下:

(1) 由于一個請求沒有明确的接收者,那麼就不能保證它一定會被處理,該請求可能一直到鍊的末端都得不到處理;一個請求也可能因職責鍊沒有被正确配置而得不到處理。

(2) 對于比較長的職責鍊,請求的處理可能涉及到多個處理對象,系統性能将受到一定影響,而且在進行代碼調試時不太友善。

(3) 如果建鍊不當,可能會造成循環調用,将導緻系統陷入死循環。

3.适用場景

在以下情況下可以考慮使用職責鍊模式:

(1) 有多個對象可以處理同一個請求,具體哪個對象處理該請求待運作時刻再确定,用戶端隻需将請求送出到鍊上,而無須關心請求的處理對象是誰以及它是如何處理的。

(2) 在不明确指定接收者的情況下,向多個對象中的一個送出一個請求。

(3) 可動态指定一組對象處理請求,用戶端可以動态建立職責鍊來處理請求,還可以改變鍊中處理者之間的先後次序。

實戰,正好學習了,就應用在項目中了

/**
 * @auther fanxuebo
 * @desc 責任鍊模式抽象類
 * @Company 假裝加密
 * @create 2018/11/22 13:56
 */
public abstract class ChainOfDutyService {

    protected ChainOfDutyService handlerService;//後繼者

    public void setHandlerService(ChainOfDutyService handlerService) { //設定後繼者
        this.handlerService = handlerService;
    }

    public abstract void processRequest(CgpCbmRfMain cgpCbmRfMain);//處理邏輯的方法
}
           
/**
 * @auther fanxuebo
 * @desc 責任鍊模式實作,處理者1
 * @Company 假裝加密
 * @create 2018/11/22 13:58
 */
@Service
public class HandlerQuotaAdjServiceImpl extends ChainOfDutyService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HandlerQuotaAdjServiceImpl.class);

    @Transactional
    @Override
    public void processRequest(CgpCbmRfMain cgpCbmRfMain) {
        if ("quotaAdj".equals(cgpCbmRfMain.getApplyType())) {
            略
        } else {
            this.handlerService.processRequest(cgpCbmRfMain);
        }
    }
}
           
/**
 * @auther fanxuebo
 * @desc 責任鍊模式實作,處理者2
 * @Company 假裝加密
 * @create 2018/11/22 14:19
 */
@Service
public class HandlerNewStoreApplyServiceImpl extends ChainOfDutyService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HandlerNewStoreApplyServiceImpl.class);

    @Transactional
    @Override
    public void processRequest(CgpCbmRfMain cgpCbmRfMain) {
        if ("newStoreApply".equals(cgpCbmRfMain.getApplyType())) {
           略
        } else {
            this.handlerService.processRequest(cgpCbmRfMain);
        }
    }
}
           
/**
 * @auther fanxuebo
 * @desc 責任鍊模式實作,處理者3
 * @Company 假裝加密
 * @create 2018/11/22 14:22
 */
@Service
public class HandlerQuotaApplyServiceImpl extends ChainOfDutyService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HandlerNewStoreApplyServiceImpl.class);

    @Transactional
    @Override
    public void processRequest(CgpCbmRfMain cgpCbmRfMain) {
        if ("quotaApply".equals(cgpCbmRfMain.getApplyType())) {
            略
        } else {
            LOGGER.error("不存在的申請類型");
            throw new RuntimeException();
        }
    }
}
           
/**
 * @auther fanxuebo
 * @desc 實際業務類,使用責任鍊設計模式
 * @Company 假裝加密
 * @create 2018/11/23 11:55
 */
@SuppressWarnings("all")
@Service
public class HandlerApprovalServiceImpl implements HandlerApprovalService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HandlerApprovalServiceImpl.class);

    @Autowired
    private HandlerQuotaAdjService handlerQuotaAdjService;
    @Autowired
    private HandlerNewStoreApplyService handlerNewStoreApplyService;
    @Autowired
    private HandlerQuotaApplyService handlerQuotaApplyService;

    /**
     * @Author fanxuebo
     * @Date 2018/11/23 11:59
     * @Description 實際業務方法
     **/
    @Transactional
    @Override
    public CommonResDto toHandlerApproval(CgpCbmRfMain cgpCbmRfMain) {
       略
            //1、建立具體處理者類(該處已交由Spring管理)
            //2、設定責任鍊
            handlerQuotaAdjService.setHandlerService(handlerNewStoreApplyService);
            handlerNewStoreApplyService.setHandlerService(handlerQuotaApplyService);
            //3、由首個設定責任鍊的具體處理類開始調用
            handlerQuotaAdjService.processRequest(cgpCbmRfMain);
        
        略
    }
}
           

一直在模仿,一直在超越!

繼續閱讀