設計模式的學習(12)責任鏈模式

責任鏈模式

責任鏈模式(Chain of Responsibility Pattern)爲一個請求建立了一個接收者對象的鏈。在這種模式中,一般每一個接收者都包含對另外一個接收者的引用,若是一個接收者對象不能處理該請求,那麼它會把相同的請求傳給下一個接收者,依此類推,直到請求被處理爲止。這種模式對請求的發送者和處理者進行解耦,屬於行爲型模式。java

意圖:避免請求發送者與接收者耦合在一塊兒,讓多個對象都有可能接收請求,將這些對象鏈接成一條鏈,而且沿着這條鏈傳遞請求,直到有對象處理它爲止。mybatis

主要解決:職責鏈上的處理者負責處理請求,客戶只須要將請求發送到職責鏈上便可,無須關心請求的處理細節和請求的傳遞,因此職責鏈將請求的發送者和請求的處理者解耦了。jsp

什麼時候使用:在處理消息的時候以過濾不少道。ide

如何解決:攔截的類都實現統一接口。性能

關鍵代碼:Handler 裏面聚合它本身,在 HandlerRequest 裏判斷是否合適,若是沒達到條件則向下傳遞,向誰傳遞以前 set 進去。this

應用實例: 一、紅樓夢中的"擊鼓傳花"。 二、JS 中的事件冒泡。 三、JAVA WEB 中 Apache Tomcat 對 Encoding 的處理,Struts2 的攔截器,jsp servlet 的 Filter。spa

優勢: 一、下降耦合度。它將請求的發送者和接收者解耦。 二、簡化了對象。使得對象不須要知道鏈的結構。 三、加強給對象指派職責的靈活性。經過改變鏈內的成員或者調動它們的次序,容許動態地新增或者刪除責任。 四、增長新的請求處理類很方便。debug

缺點: 一、不能保證請求必定被接收。 二、系統性能將受到必定影響,並且在進行代碼調試時不太方便,可能會形成循環調用。 三、可能不容易觀察運行時的特徵,有礙於除錯。設計

使用場景: 一、有多個對象能夠處理同一個請求,具體哪一個對象處理該請求由運行時刻自動肯定。 二、在不明確指定接收者的狀況下,向多個對象中的一個提交一個請求。 三、可動態指定一組對象處理請求。調試

注意事項:在 JAVA WEB 中遇到不少應用。

實現

咱們建立抽象類 AbstractLogger,帶有詳細的日誌記錄級別。而後咱們建立三種類型的記錄器,都擴展了 AbstractLogger。每一個記錄器消息的級別是否屬於本身的級別,若是是則相應地打印出來,不然將不打印並把消息傳給下一個記錄器。

步驟 1

建立抽象的記錄器類。

package com.cn.design_pattern.chain_of_responsibility_pattern;

/**
 * 
 * 抽象的責任鏈父類,定義了詳細的日誌等級
 * 
 */
public abstract class AbstractLogger {
	public static int INFO = 1;
	public static int DEBUG = 2;
	public static int ERROR = 3;

	protected int level;

	// 責任鏈中的下一個元素
	protected AbstractLogger nextLogger;

	public void setNextLogger(AbstractLogger nextLogger) {
		this.nextLogger = nextLogger;
	}

	public void logMessage(int level, String message) {
		if (this.level <= level) {
			write(message);
		}
		if (nextLogger != null) {
			nextLogger.logMessage(level, message);
		}
	}

	abstract protected void write(String message);
}

步驟 2

建立擴展了該記錄器類的實體類。

package com.cn.design_pattern.chain_of_responsibility_pattern.impl;

import com.cn.design_pattern.chain_of_responsibility_pattern.AbstractLogger;

public class ConsoleLogger extends AbstractLogger {

	public ConsoleLogger(int level) {
		this.level = level;
	}

	@Override
	protected void write(String message) {
		System.out.println("Standard Console::Logger: " + message);
	}

}

 

package com.cn.design_pattern.chain_of_responsibility_pattern.impl;

import com.cn.design_pattern.chain_of_responsibility_pattern.AbstractLogger;

public class ErrorLogger extends AbstractLogger {

	public ErrorLogger(int level) {
		this.level = level;
	}

	@Override
	protected void write(String message) {
		System.out.println("Error Console::Logger: " + message);
	}

}

 

package com.cn.design_pattern.chain_of_responsibility_pattern.impl;

import com.cn.design_pattern.chain_of_responsibility_pattern.AbstractLogger;

public class FileLogger extends AbstractLogger {

	public FileLogger(int level) {
		this.level = level;
	}

	@Override
	protected void write(String message) {
		System.out.println("File::Logger: " + message);
	}

}

步驟 3

建立不一樣類型的記錄器。賦予它們不一樣的錯誤級別,並在每一個記錄器中設置下一個記錄器。每一個記錄器中的下一個記錄器表明的是鏈的一部分。

package com.cn.design_pattern.chain_of_responsibility_pattern;

import com.cn.design_pattern.chain_of_responsibility_pattern.impl.ConsoleLogger;
import com.cn.design_pattern.chain_of_responsibility_pattern.impl.ErrorLogger;
import com.cn.design_pattern.chain_of_responsibility_pattern.impl.FileLogger;

public class Main {

	private static AbstractLogger getChainOfLoggers() {

		AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
		AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
		AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);

		errorLogger.setNextLogger(fileLogger);
		fileLogger.setNextLogger(consoleLogger);

		return errorLogger;
	}

	public static void main(String[] args) {
		AbstractLogger loggerChain = getChainOfLoggers();

		loggerChain.logMessage(AbstractLogger.INFO, "This is an information.");

		loggerChain.logMessage(AbstractLogger.DEBUG,
				"This is an debug level information.");

		loggerChain.logMessage(AbstractLogger.ERROR,
				"This is an error information.");
	}
}

步驟 4

執行程序,輸出結果:

Standard Console::Logger: This is an information.
File::Logger: This is an debug level information.
Standard Console::Logger: This is an debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.

延伸

在責任鏈的設計中,首先須要抽象出一個全部過濾器的父類,並定義處理請求的方法。

而後能夠實現多個過濾器的子類,分別重寫本身的過濾器方法,即每個子過濾器的功能不一樣。

要注意,由於過濾器是一個鏈,因此,多個過濾器實現類是存在執行的先後順序的。因此前面的過濾器,須要持有下一個過濾器對象,在處理方法中,執行完本身的邏輯後,經過這個對象,來調用下一個過濾器方法。

直到過濾器所有運行完畢,再將處理後的請求丟給真正的接收者。

JAVA 的filter dubbo的過濾器,mybatis的plugins都是基於責任鏈模式

public final class ApplicationFilterChain implements FilterChain {
    private int pos = 0; //當前執行filter的offset
    private int n; //當前filter的數量
    private ApplicationFilterConfig[] filters;  //filter配置類,經過getFilter()方法獲取Filter
    private Servlet servlet
  
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) {
        if (pos < n) {
            ApplicationFilterConfig filterConfig = filters[pos++];
            Filter filter = filterConfig.getFilter();
            filter.doFilter(request, response, this);
        } else {
            // filter都處理完畢後,執行servlet
            servlet.service(request, response);
        }
    }
  
}

 

相關文章
相關標籤/搜索