使用責任鏈模式動態綁定多實現類實例


摘要

  摘要: 由於業務場景復雜,一個算法需要開發行為變化多端的多個實現類,然后在系統運行時根據不同場景裝載不同的類實例。為了使源碼具有更好的可擴展性和可重用性,在借鑒前人處理方法的基礎上,介紹在Spring Boot項目中,基於責任鏈模式實現動態匹配相關實現類示例,並調用其中的函數。

前言

  責任鏈模式(Chain of Responsibility Pattern)定義:責任鏈模式是一種對象的行為模式。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端並不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任,實現請求對象與處理對象之間的解耦。

  在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理此請求,那么它會把此請求傳給下一個接收者,依此類推。責任鏈可能是一條直線、一個環鏈或者一棵樹結構的一部分。

  欲了解更多相關知識點請移步《Spring 動態綁定多實現類實例綜述》。

業務場景回顧

  需求描述:定制一個繪圖工具,她根據客戶端發送的指令可以畫出正方形、矩形、圓形和三角形等各種各樣的幾何圖形。例如,當客戶端需要繪制三角形的時候,就調用繪制三角形的方法;當需要繪制圓形的時候,就調用繪制圓形的方法。

案例分析

  抽象處理者角色ShapeHandler代碼如下:

/**
 * 抽象處理者
 *
 * @author Wiener
 * @date 2021/1/13
 */
public abstract class ShapeHandler {

    public abstract void draw(String code);
    
    // 持有后繼責任對象
    protected ShapeHandler next;

    public ShapeHandler getNext() {
        return next;
    }
    public void setNext(ShapeHandler next) {
        this.next = next;
    }
}

  定義兩個具體處理者TriangleHandler和CircleHandler:

import org.springframework.stereotype.Service;

/**
 * TODO
 *
 * @author Wiener
 * @date 2021/1/13
 */
@Service
public class TriangleHandler extends ShapeHandler{
    @Override
    public void draw(String code) {
        //判斷是否能夠處理當前請求
        if ("triangle".equals(code)) {
            System.out.println("Inside TriangleHandler::draw() method.");
        } else {
            //由下一個處理者處理
            getNext().draw(code);
        }
    }
}

// ---我是分割線---

import org.springframework.stereotype.Service;

/**
 * TODO
 *
 * @author Wiener
 * @date 2021/1/13
 */
@Service
public class CircleHandler extends ShapeHandler {
    @Override
    public void draw(String code) {
        if ("circle".equals(code)) {
            System.out.println("Inside CircleHandler::draw() method.");
        } else {
            getNext().draw(code);
        }
    }
}

  這里省略畫圖工具的其它兩個實現類,請讀者自行編碼。其實,不加也沒有關系,兩個處理者已經滿足我們的測試需求。下面一段代碼用於構建一個繪圖工具調度中心,其核心是對每個ShapeHandler的子類都綁定下一個需要執行的ShapeHandler子類,從而構造一個完整的鏈式調用。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 構造調用鏈
 *
 * @author Wiener
 * @date 2021/1/13
 */
@Component
public class ShapeHandlerChain implements ApplicationContextAware, InitializingBean {

    private ApplicationContext applicationContext;
    private ShapeHandler header;

    public void toDraw(String code) {
        header.draw(code);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, ShapeHandler> beansOfTypeMap = applicationContext.getBeansOfType(ShapeHandler.class);
        if (beansOfTypeMap == null || beansOfTypeMap.size() == 0) {
            return;
        }
        List<ShapeHandler> handlers = beansOfTypeMap.values().stream().collect(Collectors.toList());
        int size = handlers.size();
        for (int i = 0; i < size; i++) {
            ShapeHandler shapeHandler = handlers.get(i);
            if (i != size - 1) {
                shapeHandler.setNext(handlers.get(i + 1));
            }
        }
        header = handlers.get(0);
    }
}

  我們只需要在客戶端向函數toDraw(String code)傳入約定的入參circle和triangle等即可完成方法調用。如果想為繪圖工具類添加新的繪圖方法五角星,只需要讓五角星類繼承超類ShapeHandler,然后重寫(Override)draw函數即可,不用修改其它的已有繪圖類。

  下面蜻蜓點水般地介紹一下函數getBeansOfType(Class type)。一個類如果由Spring IoC容器管理,則 ApplicationContext的getBeansOfType這個函數就能返回此類的全部子類,實現方便地管理某個類的全部派生類實例;值得注意的是,此函數不返回抽象類。

結束語

  繪圖工具類在不同的條件下會使用不同的繪圖方法, 本文介紹了使用責任鏈模式動態綁定畫圖實例的方法。文章到這里就結束了,看完之后你有什么想法想要跟大家分享呢?評論區在等着你!

Reference


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM