在数据结构中有一种结构叫做 链表,从表头开始,通过下一节点的引用而连接起来形成一条链,每个节点可以断开再连接,结构比较灵活。如果把这种思想应用到编程中,构建这样的结构,那么每一个节点就可以映射为对象,每个对象都拥有一些共同的处理和独特处理逻辑,请求或提交从链头开始,逐一向下传递,直到这个请求被处理为止。正是基于这样的思想,前人提出了 责任链设计模型式。责任链模式很好的可以解决类似我们行政请假时,请假天数不同走的流程不同这样的场景。附行为型设计模式系列文章列表:
责任链模式(Chain of Responsibility)是一种结构简单的行为型模式,从一定程度上来说只有请求处理者对象这一种角色,其官方定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止(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.)责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果,使得多个处理对象有机会处理请求,从而实现请求发送者与请求接收者之间的解耦,把这些对象连成一条链,并把请求沿着这条链进行传递,直到完成请求的处理。请求发送者并不需要哪一个对象处理这个请求,因为总有一个请求接收者进行处理。在责任链模式中,由于请求的处理对象要形成一条链,所以每一个处理对象都要保存下一个处理对象的引用,在实际的应用中不宜拘泥于这种标准情况下,也可以是一个任务由链上的所有节点完成类似组装车间的模式总之,无论是学习任何模式都不能拘泥于所谓的标准,我这里是只举了一个例子,也不是说一定要这样做,要我说责任链的模式的核心思想在于“链”
抽象处理对象一般需要完成:处理请求和分发请求至下一节点
//抽象处理者角色,为了形成链式结构,必须持有下一个处理者的引用和拥有自己处理逻辑,甚至还可以持有上一个处理者的引用形成双向链表的结构
public abstract class AbstractHander {
protected AbstractHander nextHander;
/**
*
* @param conditionStr 用于选择下一个处理者的条件字符串
*/
public abstract void handle(String conditionStr);
/**
* 设置下一个处理者的引用
* @param hander
*/
public abstract void setNextHander(AbstractHander hander);
}
public class ConcreteHander extends AbstractHander {
@Override
public void handle(String conditionStr) {
//如果传入的条件符合,则自己处理
if("Hander".equals(conditionStr)){
System.out.println("**条件符合,由ConcreteHander自己处理这个请求");
return;
}else{
System.out.println("##条件不符合,由ConcreteHander转发这个请求到下一个处理者");
if(nextHander!=null){
nextHander.handle(conditionStr);//否则转到下一个处理者
}
}
}
@Override
public void setNextHander(AbstractHander hander) {
this.nextHander=hander;
}
}
public class ConcreteHanderA extends AbstractHander {
@Override
public void handle(String conditionStr) {
//如果传入的条件符合,则自己处理
if("HanderA".equals(conditionStr)){
System.out.println("**条件符合,由ConcreteHanderA自己处理这个请求");
return;
}else{
System.out.println("##条件不符合,由ConcreteHanderA转发这个请求到下一个处理者");
if(nextHander!=null){
nextHander.handle(conditionStr);//否则转到下一个处理者
}
}
}
@Override
public void setNextHander(AbstractHander hander) {
this.nextHander=hander;
}
}
public class ConcreteHanderB extends AbstractHander {
@Override
public void handle(String conditionStr) {
//如果传入的条件符合,则自己处理
if("HanderB".equals(conditionStr)){
System.out.println("**条件符合,由ConcreteHanderB自己处理这个请求");
return;
}else{
System.out.println("##条件不符合,由ConcreteHanderB转发这个请求到下一个处理者");
if(nextHander!=null){
nextHander.handle(conditionStr);//否则转到下一个处理者
}
}
}
@Override
public void setNextHander(AbstractHander hander) {
this.nextHander=hander;
}
}
测试
public class ResponClicent {
public static void main(String[] args) {
//初始化 责任链
ConcreteHander hander=new ConcreteHander();
ConcreteHanderA handerA=new ConcreteHanderA();
hander.setNextHander(handerA);
ConcreteHanderB handerB=new ConcreteHanderB();
handerA.setNextHander(handerB);
hander.handle("HanderB");
}
}
Java 的常见的23种模式中并不是完全独立的,在很多情况下都是可以互相结合使用,灵活的结合不同模式,才能更好提高的编码质量。在责任链模式中一个请求发送到链中后,前一节点消费部分消息,然后交由后续
节点继续处理,最终可以有处理结果也可以没有处理结果,也就是可以理解成每一个对象处理者在接到请求的时候,都需要按顺序先去判断是否有能力处理,那么通过融合模板方法模式,各个实现类只要关注的自己业务逻辑就成了,至于说什么事要自己处理,那就让父类去决定好了,也就是说父类实现了请求传递的功能,子类实现请求的处理,符合单一职责原则,各个实现类只完成一个动作或逻辑。接下来,以行政请假流程,假如请假2天以内,直接由直系领导批准,2天以上15天以内由部门领导批准为例:
/**
*
* @author Crazy.Mo
* 请求的级别枚举类
*/
public enum Rank {
DIRECT, DEPART,UNLEAGLE
}
public class ResonseResult {
private String result;
public ResonseResult(String result) {
this.result = result;
}
public String getResult() {
return result;
}
}
public class MyRequest {
private Rank rank;
private int days;
private String content;
public MyRequest(int day , String content) {
super();
this.days = day;
this.content = content;
}
public Rank getRank() {
//这里预定义了2天以内直接由直系领导申请
if(days>0&&days<=2){
this.rank=Rank.DIRECT;
}else if(days>2&&days<=15){
this.rank=Rank.DEPART;
}else{
this.rank=Rank.UNLEAGLE;
}
return this.rank;
}
public String getContent(){
return this.content;
}
public int getDays() {
return days;
}
}
在抽象处理对象中结合模板方法模式,先判断请假请求是哪个级别
ackage responsibilitymethod;
public abstract class AbstractLeader {
private AbstractLeader nextLeader;
/**
* 每个处理者都必须对请求做出处理
*/
public final ResonseResult handleMessage(MyRequest myRequest) {
ResonseResult ResonseResult = null;
// 判断是否是自己的处理级别
if (myRequest.getDays()<=limitDay()&&(this.getLeaderRank().equals(myRequest.getRank()))) {
ResonseResult = this.handle(myRequest);
} else { // 不属于自己的处理级别
// 判断是否有下一个处理者
if (this.nextLeader != null) {
System.out.println("当前级别无法处理,传递到下一级");
ResonseResult = this.nextLeader.handleMessage(myRequest);
} else {
// 没有适当的处理者,业务自行处理
System.out.println("没有适当的处理者,业务无法处理");
}
}
return ResonseResult;
}
/**
* 设置下一个处理者
*/
public void setNext(AbstractLeader nextLeader) {
this.nextLeader = nextLeader;
}
/**
* 每个处理者都有一个处理级别
* @return
*/
protected abstract Rank getLeaderRank();
/**
* 每个处理者都必须实现处理任务的逻辑
*/
protected abstract ResonseResult handle(MyRequest myrequest);
protected abstract int limitDay();
}
public class DirectLeader extends AbstractLeader {
@Override
protected Rank getLeaderRank() {
return Rank.DIRECT;
}
@Override
protected ResonseResult handle(MyRequest myrequest) {
return new ResonseResult(myrequest.getContent()+"已处理成功,直系领导已经批准,流程结束");
}
@Override
protected int limitDay() {
return 2;
}
}
public class DepartLeader extends AbstractLeader {
@Override
protected Rank getLeaderRank() {
return Rank.DEPART;
}
@Override
protected ResonseResult handle(MyRequest myrequest) {
return new ResonseResult(myrequest.getContent()+"已处理成功,部门领导已经批准,流程结束");
}
@Override
protected int limitDay() {
return 15;
}
}
public class ResponClient {
public static void main(String[] args) {
AbstractLeader handler1 = new DirectLeader();
AbstractLeader handler2 = new DepartLeader();
handler1.setNext(handler2);
//提交请求,返回结果
System.out.println(handler1.handleMessage(new MyRequest(10,"因身体不舒服请假10天")).getResult());
System.out.println(handler1.handleMessage(new MyRequest(1,"因事请假1天")).getResult());
}
}
发送者不需要知道接收者的具体信息,只要交给一个接收者就可以了。降低了客户与系统的耦合程度对于每一个具体的处理对象来讲,它只需要保存其下一个处理对象的引用就可以了,这样就使得处理对象之间的耦合度降低责任链的结构是在客户端定义的,这就使得可以随时增加或者修改责任链的结构,增强了指派责任的灵活性。
源码传送门