Java设计模式----职责链模式 1.职责链模式 2.代码实现 3.总结

Java设计模式----职责链模式
1.职责链模式
2.代码实现
3.总结

假如有这样一个场景:小红做作业的时候,有一道题不会做,这时候,小红就去问同桌小明怎么做,小明表示也不会做,于是,小红又去问学习委员小黄,小黄也不会做,最后,小红不得不请教老师这个问题,老师给江红讲解了这个问题

从上述场景中,我们看到小红依次找了 小明、小黄、老师,如果用流程图表示,那么就是:

Java设计模式----职责链模式
1.职责链模式
2.代码实现
3.总结 

看起来就像是一条链条,一个请求,在链条上的各个节点间传递,知道请求被响应,这就是职责链模式


职责链模式(Chain of Responsibility): 将能够处理同一类请求的对象连成一条链,使这些对象都有机会处理请求,所提交的请求沿着链传递。从而避免请求的发送者和接受者之间的耦合关系。链上的对象逐个判断是否有能力处理该请求,如果能则就处理,如果不能,则传给链上的下一个对象。直到有一个对象处理它为止。       ----《大话设计模式》

职责链模式的结构图图如下:

Java设计模式----职责链模式
1.职责链模式
2.代码实现
3.总结

这里的关键点,在于链上的节点Handler,持有一个指向下一节点的引用,实现的思想类似于数据结构中的链表。需要注意的是,对于一个请求,请求者和Handler都不知道该请求会在哪一个Handler被处理,每个Handler对象都要充分考虑清楚如何处理,防止请求走到最后一个Handler而无法被处理的情况发生。


2.代码实现

对于开篇的场景,我做了代码的演示。小红提出一个问题,封装为一个请求实体,我采用枚举类Request封装问题,按照难度等级分为不同请求对象:

/**
 * 请求封装,使用枚举,分为:简单问题,普通问题,困难问题,超级难题
 */
enum Request {
    SIMPLE_QUESTION,
    NORMAL_QUESTION,
    HARD_QUESTION,
    SUPER_HARD_QUESTION
}

然后是创建问题解答者的抽象类,RequestHandler,关键点是,此类聚合有本类实体other,代表着“下一个”节点,即问题的传播方向。定义了抽象方法answer,其子类需要override该方法以对请求进行处理。

/**
 * 问题回答者的抽象类
 */
abstract class RequestHandler {
    protected String name;
    public RequestHandler(String name) {
        this.name = name;
    }

    protected RequestHandler other;
    public void setHandler(RequestHandler handler) {
        other = handler;
    }

    public abstract void answer(Request question);
}

RequestHandler的三个子类:   分别代表同桌、学习委员、老师, 他们需要实现answer方法,对请求进行处理,注意要考虑周全请求无法处理的情况,也需要合理的结束请求在这条链上传播的过程。

/**
 * 同桌
 */
class Deskmate extends RequestHandler {

    public Deskmate(String name) {
        super(name);
    }

    @Override
    public void answer(Request question) {
        if (Request.SIMPLE_QUESTION == question) {
            System.out.printf("%s 解答了问题。
",name);
        }else{
            other.answer(question);
        }
    }
}

/**
 * 学习委员
 */
class StudySecretary extends RequestHandler {

    public StudySecretary(String name) {
        super(name);
    }

    @Override
    public void answer(Request question) {
        if (Request.SIMPLE_QUESTION == question || Request.NORMAL_QUESTION == question) {
            System.out.printf("%s 解答了问题。
",name);
        } else{
            other.answer(question);
        }
    }
}

/**
 * 老师
 */
class Teacher extends RequestHandler {

    public Teacher(String name) {
        super(name);
    }

    @Override
    public void answer(Request question) {
        if (Request.SIMPLE_QUESTION == question || Request.NORMAL_QUESTION == question ||
                Request.HARD_QUESTION == question) {
            System.out.printf("%s 解答了问题。
",name);
        } else {
            System.out.println("问题太难,没人会。");
        }
    }
}

最后就是客户端调用,首先创建出三个Hanlder子类的实例, 然后给"同桌"和“学习委员”设置后继者,这样,就由“同桌”、“学习委员”、“老师”三个“节点”连成了一条链。“老师”没有设置后继者,为终点。

问题的提问,我这里从“同桌”开始, 实际情况中,并不一定非得从“起点”开始, 并且节点之间的顺序,也可以改变。

public class ChainDemo {
    public static void main(String[] args) {
        // 职责链上的"节点"
        RequestHandler deskmate = new Deskmate("同桌小明");
        RequestHandler studySecretaryre = new StudySecretary("学习委员小黄");
        RequestHandler teacher = new Teacher("老师");

        // 设置"后继者"
        deskmate.setHandler(studySecretaryre);
        studySecretaryre.setHandler(teacher);

        //从同桌开始提问
        deskmate.answer(Request.SIMPLE_QUESTION);
        deskmate.answer(Request.NORMAL_QUESTION);
        deskmate.answer(Request.HARD_QUESTION);
        deskmate.answer(Request.SUPER_HARD_QUESTION);
    }
}

输出结果

同桌小明 解答了问题。
学习委员小黄 解答了问题。
老师 解答了问题。
问题太难,没人会。

3.总结

通过一个场景:“教室里小红问同桌问题,同桌不会问学习委员,学习委员不会问老师”,这样一个生活例子,介绍了职责链模式。职责链模式的优点是降低了请求发送者和请求接收者的耦合度, 因为请求者只需要把问题发送给一个接收者就可以了,不需要关心具体是哪个接收者处理的问题结果。很明显,职责链模式,很适合在流程审批这类场景中应用,比如在公司发出一条请假审批, 不同职位对于员工请假天数的批准,有不同的权限,比如直接主管职能批准2天及以下,总监能批准5天......

职责链模式扩展起来也比较方便,就像数据结构中链表的插入效率很高一个道理,职责链中在某两个节点之间插入一个新的节点,也只需要更改前一个节点的“后继者”而已。

总之,应用任何实际模式,都要按需应用,不可滥用,比如如果流程成环了,就要注意职责链模式是否合适;或者是节点过多,那么以后万一请求变化了,每一个链上的节点都需要修改,这样就不大合适,这种场景,就应该考虑一个“中间人”的角色接收请求再转给其他实际接收者的模式了。