小话设计模式(十三)职责链模式

职责链(Chain of Responsibility)职责链模式是一种行为模式,当多个对象都有机会处理请求的时候,为了避免请求的发送者和接收者之间的耦合关系,我们使用职责链模式将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

职责链模式最常用的地方就是在UI组件响应点击事件的时候,今天我们就以此为例。

首先我们定义了一个基类:

public class Widget 
{
	protected Widget _parent;
	public Widget(Widget parent)
	{
		_parent = parent;
	}
	public virtual bool CanResponse(int x, int y)
	{
		return false;
	}
	public virtual void HandleTouch(int x, int y)
	{
		if (CanResponse(x, y)) {
			DoHandleTouch (x, y);
		} else {
			if (_parent != null) {
				_parent.HandleTouch (x, y);
			}
		}
	}
	protected virtual void DoHandleTouch(int x, int y)
	{
		//TODO
		Console.WriteLine("Touch on widget");
	}
}

在这个Widget基类里面,就定义了职责链的一些基本操作:连接后继者(parent),是否响应事件(CanResponse),传递事件(HandleTouch),处理事件(DoHandleTouch)。

我们可以实现继承自Widget的两个类:

public class Button : Widget
{
	protected int _x;
	protected int _y;
	protected int _w;
	protected int _h;
	public Button(Widget parent, int x, int y, int w, int h) : base(parent)
	{
		_x = x;
		_y = y;
		_w = w;
		_h = h;
	}
	public override bool CanResponse(int x, int y)
	{
		return ContainPoint (x, y);
	}
	protected bool ContainPoint(int x, int y)
	{
		return x >= _x && x < _x + _w && y >= _y && y < _y + _h;
	}
	protected override void DoHandleTouch(int x, int y)
	{
		//TODO
		Console.WriteLine("Touch on button");
	}
}

public class Image : Widget
{
	public Image (Widget parent) : base(parent)
	{
	}
	public override bool CanResponse(int x, int y)
	{
		return !IsTransparentAtPoint (x, y);
	}
	protected bool IsTransparentAtPoint(int x, int y)
	{
		//TODO
		return false;
	}
	protected override void DoHandleTouch(int x, int y)
	{
		//TODO
		Console.WriteLine("Touch on image");
	}
}
使用:

		Widget wdt = new Widget (null);
		Image img = new Image (wdt);
		Button btn = new Button (img, 0, 0, 100, 100);
		btn.HandleTouch (200, 300);

因为传入的x,y不在btn的区域里,所以将事件传递给了img,由img来处理事件。


职责链模式让我想起了RPG游戏里面两个很有趣的技能,护卫和伤害转移,简单实现以下:

public abstract class Battler
{
	public string Name { get; protected set;}
	public Battler(string name)
	{
		Name = name;
	}
	protected Battler _damageTaker;
	public void TransferDamageTo(Battler taker)
	{
		_damageTaker = taker;
	}
	public int HP { get; set;}
	public void BeDamaged(int dmg)
	{
		if (_damageTaker != null) {
			_damageTaker.BeDamaged (dmg);
		} else {
			HP -= dmg;
			Console.WriteLine (Name + " is damaged");
		}
	}
	public int Attack{ get; set; }
	public void AttackTo(Battler battler)
	{
		Console.WriteLine (Name + "is attacking");
		battler.BeDamaged (Attack);
	}
}

public class Hero : Battler
{
	public Hero(string name) : base(name)
	{
		HP = 100;
		Attack = 20;
	}
	public void Protect(Hero other)
	{
		other.TransferDamageTo (this);
	}
}

public class Monster : Battler
{
	public Monster(string name) : base(name)
	{
		HP = 200;
		Attack = 10;
	}
}

使用:

		Hero snow = new Hero ("snow");
		Hero pino = new Hero ("pino");
		Monster monster = new Monster ("monster");
		Monster frog = new Monster ("forg");
		pino.Protect (snow);
		pino.TransferDamageTo (monster);
		frog.AttackTo (snow);
pino护卫了snow,又将伤害转移给frog,所以当monster攻击的时候,frog承受了伤害。

这段代码算是职责链模式的变种,因为职责链模式只有本对象无法处理事件的时候才会传递给后继者,而这段代码是只有没有后继者的时候才会处理事件。



职责链模式的优点在于降低了耦合度,事件的发送者和接收者都没有对方明确的信息,而且我们可以实现多种多样的职责链结构(例如树形),而链中的对象不需要知道它所处的是怎样的结构。并且职责链模式增强了分派事件的灵活性,可以动态的修改链的结构,增加、删除或者调整顺序。

缺点在于,不能保证事件可以被处理,因为并不一定有对象可以相应事件。而且这样也增加了系统的复杂性,会增加排错的难度。


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值