設計模式--責任鏈模式ChainOfResponsibility(行為型)

benbenxiongyuan發表於2014-04-14

1 定義:

1.1 定義:Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.(使多個物件都有機會處理請求,從而避免了請求的傳送者和接受者之間的耦合關係。將這些物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有物件處理它為止。)

1.2 通用類圖:

責任鏈模式的重點是在“鏈”上,由一條鏈去處理相似的請求在鏈中決定誰來處理這個請求,並返回相應的結果。

1.3 通用程式碼:

	/**
	 * @author cbf4Life cbf4life@126.com I'm glad to share my knowledge with you
	 *         all.
	 */
	public abstract class Handler {
		private Handler nextHandler;

		// 每個處理者都必須對請求做出處理
		public final Response handlerMessage(Request request) {
			Response response = null;
			// 判斷是否是自己的處理級別
			if (this.getHandlerLevel().equals(request.getRequestLevel())) {
				response = this.echo(request);
			} else { // 不屬於自己的處理級別
				// 判斷是否有下一個處理者
				if (this.nextHandler != null) {
					response = this.nextHandler.handlerMessage(request);
				} else {
					// 沒有適當的處理者,業務自行處理
				}
			}
			return response;
		}

		// 設定下一個處理者是誰
		public void setNext(Handler _handler) {
			this.nextHandler = _handler;
		}

		// 每個處理者都有一個處理級別
		protected abstract Level getHandlerLevel();

		// 每個處理者都必須實現處理任務
		protected abstract Response echo(Request request);
	}

	// 抽象的處理者實現三個職責:一是定義一個請求的處理方法handleMessage,唯一對外開放的方法;二是定義一個鏈的編排方法setNext,設定下一個處理者;三是定                                     義了具體的請求者必須實現的兩個方法:定義自己能夠處理的級別與具體的處理任務。
	public class ConcreteHandler1 extends Handler {
		// 定義自己的處理邏輯
		protected Response echo(Request request) {
			// 完成處理邏輯
			return null;
		}

		// 設定自己的處理級別
		protected Level getHandlerLevel() {
			// 設定自己的處理級別
			return null;
		}
	}

	public class ConcreteHandler2 extends Handler {
		// 定義自己的處理邏輯
		protected Response echo(Request request) {
			// 完成處理邏輯
			return null;
		}

		// 設定自己的處理級別
		protected Level getHandlerLevel() {
			// 設定自己的處理級別
			return null;
		}
	}

	public class ConcreteHandler3 extends Handler {
		// 定義自己的處理邏輯
		protected Response echo(Request request) {
			// 完成處理邏輯
			return null;
		}

		// 設定自己的處理級別
		protected Level getHandlerLevel() {
			// 設定自己的處理級別
			return null;
		}
	}

	public class Level {
		// 定義一個請求和處理等級
	}

	public class Request {
		// 請求的等級
		public Level getRequestLevel() {
			return null;
		}
	}

	public class Response {
		// 處理者返回的資料
	}

	public class Client {
		public static void main(String[] args) {
			// 宣告出所有的處理節點
			Handler handler1 = new ConcreteHandler1();
			Handler handler2 = new ConcreteHandler2();
			Handler handler3 = new ConcreteHandler3();
			// 設定鏈中的階段順序,1-->2-->3
			handler1.setNext(handler2);
			handler2.setNext(handler3);
			// 提交請求,返回結果
			Response response = handler1.handlerMessage(new Request());
		}
	}

在實際應用中,一般會有一個封裝類對責任模式進行封裝,也就是替代Client類,直接返回鏈中第一個處理者,具體鏈的設定不需要高層次模組關係,這樣更簡化了高層次模組的呼叫,減少模組間的耦合,提高系統的靈活性。

2 優點

2.1 最顯著就是:請求和處理分開。請求者可以不用知道是誰處理的,處理者可以不用知道請求的全貌,兩者解耦,提高系統的靈活性。

2.2 承接第一點,個人認為最大的好處就是把星狀的耦合關係變成直線型的耦合關係,使原本“一對多”的耦合關係,變為“一對一”耦合(因為事件只與第一個處理物件耦合,每個處理物件又只與後面一個物件耦合)。

3 缺點

3.1 效能問題:每個請求都從鏈頭遍歷到鏈尾,特別是在鏈比較長的時候,效能是一個非常大的問題。

3.2 不便於除錯,由於採用了類似於遞迴的方式,除錯時邏輯比較複雜。

4 應用場景

責任鏈模式的核心是遮蔽了請求的處理過程(即請求者可以不用知道到底是誰來處理的)。

其表面上看來,用物件導向的“連結串列+遍歷+函式呼叫+判斷”來替換程式導向的“若干if-else判斷”,以至於我起初認為這個模式完全是為了物件導向取代if判斷而生的。

但實質上,降低了請求與處理物件之間的耦合,分析見上。

4.1某一請求根據條件,只需少數(或一個)物件處理,但卻需要在較多物件中做選擇的情況;

4.2 請求處理時,不能越權,只能按步驟判斷處理的情況;

5 注意事項

5.1 鏈長需要控制,應避免出現超長鏈的情況;

6 擴充套件

6.1某事件需要多個大物件共同參與處理的情況(每個物件處理一部分,但非每個物件每時每刻都參與的情境);[冒似此景下最能發揮效能,但要考慮設計是否有問題。。。]

7 範例

(小例,請假,因為不能越權嘛,你只能訪問直接上司。。。)

類圖如下:


原始碼

	package _10_ChainOfResponsibility;
	public abstract class Handler {
		private Handler nextHandler;

		public final AskForLeave handleMessage(AskForLeave ask) {
			AskForLeave leave = null;
			if (ask.getDays() <= this.getDays()) {
				leave = this.echo(ask);
			} else {
				if (this.nextHandler != null)
					leave = this.nextHandler.handleMessage(ask);
				else
					;// 沒有處理者
			}
			return leave;
		}

		// 設定下一者
		public void setNext(Handler handler) {
			nextHandler = handler;
		}

		// 每個處理者都有處理等級
		protected abstract int getDays();

		// 每個處理者都必須實現處理任務
		protected abstract AskForLeave echo(AskForLeave ask);
	}

	public class HeadHandler extends Handler {
		@Override
		protected int getDays() {
			return 1;
		}

		@Override
		protected AskForLeave echo(AskForLeave ask) {
			ask.setResult(true);
			return ask;
		}
	}

	public class ManagerHandler extends Handler {
		@Override
		protected int getDays() {
			return 3;
		}

		@Override
		protected AskForLeave echo(AskForLeave ask) {
			ask.setResult(true);
			return ask;
		}
	}

	public class ChiefHandler extends Handler {
		@Override
		protected int getDays() {
			return 7;
		}

		@Override
		protected AskForLeave echo(AskForLeave ask) {
			ask.setResult(true);
			return ask;
		}
	}

	public class HumanResourceHandler extends Handler {
		@Override
		protected int getDays() {
			return 15;
		}

		@Override
		protected AskForLeave echo(AskForLeave ask) {
			ask.setResult(true);
			return ask;
		}
	}

	public class AskForLeave {
		private int days;
		private boolean result = false;

		public AskForLeave(int days) {
			this.days = days;
		}

		public boolean getResult() {
			return result;
		}

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

		public int getDays() {
			return days;
		}
	}

	public class Client {
		public static void main(String[] args) {
			Handler h1 = new HeadHandler();
			Handler h2 = new ManagerHandler();
			Handler h3 = new ChiefHandler();
			Handler h4 = new HumanResourceHandler();
			h1.setNext(h2);
			h2.setNext(h3);
			h3.setNext(h4);
			AskForLeave ask1 = new AskForLeave(5);
			AskForLeave ask2 = new AskForLeave(15);
			AskForLeave ask3 = new AskForLeave(16);
			h1.handleMessage(ask1);
			System.out.println("請假5天,是否批准? " + ask1.getResult());
			h1.handleMessage(ask2);
			System.out.println("請假15天,是否批准? " + ask2.getResult());
			h1.handleMessage(ask3);
			System.out.println("請假16天,是否批准? " + ask3.getResult());
		}
	}

結果:

請假5天,是否批准? true

請假15天,是否批准? true

請假16天,是否批准? false

 

轉自:http://blog.csdn.net/ljianhui/article/details/8302415

相關文章