责任链模式(Chain of Responsibility)

Posted LoveTomato

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了责任链模式(Chain of Responsibility)相关的知识,希望对你有一定的参考价值。

模式定义

责任链模式(Chain of Responsibility): 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条对象连成一条链,并沿着这条链传递请求。

UML类图

  • 抽象处理者(Handler) :定义一个处理请求的接口。关联自身类型的变量。
  • 具体处理者(Concrete Handler): 实现 抽象处理者中的处理方法,处理请求或者传递给下个处理对象。
  • 客户端(Client):设置处理链,并调用。

代码结构

class ChainClient
	{
		 public void Run()
		{
			Handler h1 = new ConcreteHandler1();
			Handler h2 = new ConcreteHandler2();
			Handler h3 = new ConcreteHandler3();
			h1.SetSuccessor(h2);
			h2.SetSuccessor(h3);

			int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };

			foreach (int request in requests)
			{
				h1.HandleRequest(request);
			}
			Console.ReadKey();
		}
	}

	abstract class Handler
	{
		protected Handler successor;

		public void SetSuccessor(Handler successor)
		{
			this.successor = successor;
		}

		public abstract void HandleRequest(int request);
	}

	class ConcreteHandler1 : Handler
	{
		public override void HandleRequest(int request)
		{
			if (request >= 0 && request < 10)
			{
				Console.WriteLine("{0} handled request {1}",this.GetType().Name, request);
			}
			else if (successor != null)
			{
				successor.HandleRequest(request);
			}
		}
	}

	class ConcreteHandler2 : Handler
	{
		public override void HandleRequest(int request)
		{
			if (request >= 10 && request < 20)
			{
				Console.WriteLine("{0} handled request {1}",this.GetType().Name, request);
			}
			else if (successor != null)
			{
				successor.HandleRequest(request);
			}
		}
	}

	class ConcreteHandler3 : Handler
	{
		public override void HandleRequest(int request)
		{
			if (request >= 20 && request < 30)
			{
				Console.WriteLine("{0} handled request {1}",this.GetType().Name, request);
			}
			else if (successor != null)
			{
				successor.HandleRequest(request);
			}
		}
	}

情景案例

这里以大学中请假为例:少于2天班长处理,多于2天班长交给指导员处理,多于5天指导员交给系主任处理,多于30天不准。

class RealWorldChainClient
	{
		public void Run()
		{
			Approver h1 = new Monitor();
			Approver h2 = new Instructor();
			Approver h3 = new DepartmentHead();
			h1.SetSuccessor(h2);
			h2.SetSuccessor(h3);

			int[] requests = { 2, 5, 14, 35 };

			foreach (int request in requests)
			{
				h1.HandleRequest(request);
			}
			Console.ReadKey();
		}
	}

	abstract class Approver
	{
		protected Approver successor;

		public void SetSuccessor(Approver successor)
		{
			this.successor = successor;
		}

		public abstract void HandleRequest(int days);
	}

	/// <summary>
	/// 班长
	/// </summary>
	class Monitor : Approver
	{
		public override void HandleRequest(int days)
		{
			if (days >= 0 && days <= 2)
			{
				Console.WriteLine("我是班长,批准请假{0}天",days);
			}
			else if (successor != null)
			{
				successor.HandleRequest(days);
			}
		}
	}

	/// <summary>
	/// 指导员
	/// </summary>
	class Instructor : Approver
	{
		public override void HandleRequest(int days)
		{
			if (days >= 0 && days < 10)
			{
				Console.WriteLine("我是指导员,批准请假{0}天", days);
			}
			else if (successor != null)
			{
				successor.HandleRequest(days);
			}
		}
	}

	/// <summary>
	/// 系主任
	/// </summary>
	class DepartmentHead : Approver
	{
		public override void HandleRequest(int days)
		{
			if (days >= 0 && days < 30)
			{
				Console.WriteLine("我是指导员,批准请假{0}天", days);
			}
			else
			{
				Console.WriteLine("请假天数太多了,退学吧!");
			}
		}
	}

自问自答

小a:你的博客好冷清呀!!!我感觉你上面讲的例子还不如用if()....else....简单明了,整那么多类倒是增加了复杂性,感觉这个模式没必要?

LoveTomato: 啊!!!确实博客比较冷清,万事开头难吗?但开头难也要开头的吗。
回答正题 确实业务比较简单,顺序编程简单快捷。但是项目中往往是比较复杂的,比如好多网站需要用户填入的表单,后台验证数据的有效性。假设验证的指标有

  1. 必填性验证
  2. 数据类型验证(时间类型的值是否有效等)
  3. 业务验证(需要查询数据库)

这样每个验证都需要大段的代码,在if...else中维护的心情你懂的,而且每次添加项新的验证都需要修改if...else

以上是关于责任链模式(Chain of Responsibility)的主要内容,如果未能解决你的问题,请参考以下文章

责任链模式(Chain of Responsibility)

15-责任链(Chain of Responsibility)模式Ruby实现

责任链模式(Chain of Responsibility Pattern)

责任链模式(chain of responsibility)

责任链模式(Chain of Responsibility)

设计模式(13)--Chain of Responsibility(责任链模式)--行为型