责任链模式是一种常见的行为模式。
一.责任链模式的现实场景
习伟过生日邀请了很多朋友到KTV一起庆祝,为了增加欢乐的气氛,习伟建议大家一起玩击鼓传花的游戏。由习伟击鼓,大家依次往下传花,鼓声停下来时,花在谁手上就要喝酒并且还要唱一首歌。
大家都很踊跃地参加这个游戏,聚会的气氛很快热闹起来,习伟也度过了一个很快乐的生日聚会。
在上面的这个场景中,击鼓传花的这个游戏过程类似于设计模式中的责任链模式,就是要事件不断的进行传递,直到事件被执行为止。
二.责任链模式(Chain of Respinsibility Pattern)的定义
使多个对象都有处理请求的机会,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象串成一条链,并沿着这条链依次传递请求,直到有对象处理它为止。
四.责任链模式的两个角色
1.抽象处理者(Handler)角色
该角色对请求进行抽象,并定义一个方法来设定和返回对下一个处理者的引用。
2.具体处理者(Concrte Handler)角色
该角色接到请求后,可以选择将请求处理掉,或者将请求传递给下一个处理者。
由于具体处理者持有对下一个处理者的引用,因此,如果需要,具体处理者可以访问下一个处理者,把问题給下一个处理者,并以此类推。
五.责任链模式的优缺点
责任链模式中的优点
1. 责任链模式将请求和处理分开,请求者不知道是谁处理,处理者可以不用知道请求者全貌。
2. 提高系统的灵活性
命令模式的缺点
1.降低程序的性能。每个请求都是从链头遍历到链尾,当遇到链比较长的时候,性能就会大幅下降。
2.不易于调试,由于该模式采用了类似递归的方式,调试的时候逻辑比较复杂。
责任链中的节点数量需要控制,避免出现超长链的情况,这就需要设置一个最大的节点数量,一旦超过则不允许增加节点,避免责任链无意识地破化系统性能。
六.责任链模式的使用场景
责任链模式是一种常见的模式,Struts2的核心控件FilterDispatcher是一个Servlet过滤器,该控件就是采用责任链模式,可以对用户请求进行层层过滤处理。责任链模式在实际项目中的使用也是有的,其典型的应用场景如下:
1.一个请求需要一系列的处理工作。
2.业务流的处理,例如文件审批。
3.对系统进行扩展。
七.责任链模式的示例
示例代码 击鼓传花, 输者喝酒
抽象处理类Player
package com.chain.test;
public abstract class Player {
//具体做事的人
private Player dirnk;
public Player getDirnk() {
return dirnk;
}
//传入下一个具体做事的人
public void setDirnk(Player dirnk) {
this.dirnk = dirnk;
}
//传到的过程
public abstract void handle(int i);
public void next(int index) {
if(dirnk != null) {
dirnk.handle(index);
}else {
System.out.println("game over!");
}
}
}
具体处理类PlayerA
package com.chain.test;
/**
* 游戏参与者
* @author pc
*
*/
public class PlayerA extends Player {
//构造方法 传入下一个 游戏参与者
public PlayerA(Player drink) {
this.setDirnk(drink);
}
//游戏过程
@Override
public void handle(int i) {
if(i%5==1) {
System.out.println("PlayerA drink!");
}else {
System.out.println("PlayerA next!");
next(i);
}
}
}
具体处理类PlayerB
package com.chain.test;
/**
* 游戏参与者
* @author pc
*
*/
public class PlayerB extends Player {
//构造方法 传入下一个 游戏参与者
public PlayerB(Player drink) {
this.setDirnk(drink);
}
//游戏过程
@Override
public void handle(int i) {
if(i%5==2) {
System.out.println("PlayerB drink!");
}else {
System.out.println("PlayerB next!");
next(i);
}
}
}
具体处理类PlayerC
package com.chain.test;
public class PlayerC extends Player {
//构造方法 传入下一个 游戏参与者
public PlayerC(Player drink) {
this.setDirnk(drink);
}
//游戏过程
@Override
public void handle(int i) {
if(i%5==3) {
System.out.println("PlayerC drink!");
}else {
System.out.println("PlayerC next!");
next(i);
}
}
}
具体处理类PlayerD
package com.chain.test;
public class PlayerD extends Player {
//构造方法 传入下一个 游戏参与者
public PlayerD(Player drink) {
this.setDirnk(drink);
}
//游戏过程
@Override
public void handle(int i) {
if(i%5==4) {
System.out.println("PlayerD drink!");
}else {
System.out.println("PlayerD next!");
next(i);
}
}
}
具体处理类PlayerE
package com.chain.test;
public class PlayerE extends Player {
//构造方法 传入下一个 游戏参与者
public PlayerE(Player drink) {
this.setDirnk(drink);
}
//游戏过程
@Override
public void handle(int i) {
if(i%5==0) {
System.out.println("PlayerE drink!");
}else {
System.out.println("PlayerE next!");
next(i);
}
}
}
测试类:
package com.chain.test;
/**
* 测试
* @author pc
*
*/
public class TestChain {
public static void main(String args[]){
//创建一个链
PlayerA playerA = null;
PlayerE playerE=new PlayerE(playerA);
PlayerD playerD=new PlayerD(playerE);
PlayerC playerC=new PlayerC(playerD);
PlayerB playerB=new PlayerB(playerC);
//PlayerA playerA=new PlayerA(playerB);
playerA=new PlayerA(playerB);
//击鼓下停下来
playerA.handle(5);
}
}
运行结果:
PlayerA next!
PlayerB next!
PlayerC next!
PlayerD next!
PlayerE drink!
但是实际生活的传花游戏,一般循环 ,这就需要改造每个类的 if(i%N==0) 即可实现
原文:https://blog.csdn.net/wenzhi20102321/article/details/79333899