设计模式讲解与代码实践(十四)——职责链

本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!

1 目的

职责链(Chain of responsibility)模式使多个对象均有机会处理同一请求,请求在可能处理它的对象间按既定顺序流转,直至被处理。职责链将请求与实际处理它的对象解耦。职责链最常使用的场景是UI中对鼠标、键盘事件的处理。

2 基本形态

职责链的基本形态如类图2-1所示。
设计模式讲解与代码实践(十四)——职责链_第1张图片
图2-1 职责链类图

职责链模式各对象间的调用关系如对象图2-2所示。
设计模式讲解与代码实践(十四)——职责链_第2张图片
图2-2 职责链对象图

3 参与者

结合图2-1,下面介绍各类在职责链设计模式中扮演的角色。
3.1 Handler
Handler是处理器接口(或抽象类),包含了各请求处理接口方法。Handler维护了Handler类型的后继请求处理器实例。
3.2 ConcreteHandler
ConcreteHandler1和ConcreteHandler2是具体的处理器。它们实现了Handler接口,实现对请求的处理。在处理内部,ConcreteHandler判断请求是否在自己的处理范围内,如果在则处理请求;如果不在则将请求向后继处理器传递。
在实际应用中,可以在ConcreteHandler中指定其后继处理器类型,即在构造方法里实例化后继处理器;也可以提供设置后继处理器的方法由客户组织职责链。本文后面的示例采用了后一种形式。
3.3 Client
Client是客户类,是职责链模式的使用者。Client实例化初始的处理器(或组织整条职责链),将请求传递给初始处理器处理。

4 代码实践

下面我们用一个业务场景实例来进一步讲解职责链的使用。
4.1 场景介绍
某电信系统欠费管理模块对欠费进行处理。视欠费用户的类型不同,欠费处理形式不同。
以下各节将介绍该场景各类的具体实现及其在职责链设计模式中所对应的参与者角色。
4.2 ArrearHandler
ArrearHandler是欠费处理器接口,声明了处理欠费方法handleArrear。对应于职责链模式的参与者,ArrearHandler是处理器接口Handler。下面的代码给出了ArrearHandler的声明。

package demo.designpattern.chainofresponsibility;

/**
 * 欠费处理接口
 * Created by LiMingzi on 2017/7/28.
 */
public abstract class ArrearHandler {
    /**
     * 设置后续处理器
     * @param nextHandler 后续处理器
     */
    public void setNextHandler(ArrearHandler nextHandler) {
        this.nextHandler=nextHandler;
    }
    /**
     * 处理欠费
     * @param phoneNumber 电话号码
     * @param amountInArrear 欠费金额
     */
    abstract void handleArrear(String phoneNumber,double amountInArrear);
    // 后续处理器
     ArrearHandler nextHandler=null;
}

上述代码中,ArrearHandler被声明为抽象类。22行,声明了ArrearHandler类型的后继处理器成员变量nextHandler。12行,声明了设置后继处理器对象的方法setNextHandler。20行,声明了处理欠费抽象方法handleArrear。
4.3 CompanyUserArrearHandler
CompanyUserArrearHandler是公司用户欠费处理器,派生于ArrearHandler类。对应于职责链模式的参与者,CompanyUserArrearHandler是具体处理器ConcreteHandler。下面的代码给出了CompanyUserArrearHandler的声明。

package demo.designpattern.chainofresponsibility;

/**
 * 公司用户欠费处理器
 * Created by LiMingzi on 2017/7/28.
 */
public class CompanyUserArrearHandler extends ArrearHandler {
    /**
     * 处理欠费
     *
     * @param phoneNumber    电话号码
     * @param amountInArrear 欠费金额
     */
    @Override
    public void handleArrear(String phoneNumber, double amountInArrear) {
        if(isCompanyUser(phoneNumber)){
            System.out.println("向公司财务部发送催款邮件,欠费号码:"+phoneNumber+",欠费金额:"+amountInArrear);
        }else{
            if(nextHandler!=null) {
                nextHandler.handleArrear(phoneNumber, amountInArrear);
            }
        }
    }

    /**
     * 是否为公司用户
     * @param phoneNumber 电话号码
     * @return 是否为公司用户
     */
    private boolean isCompanyUser(String phoneNumber){
        // demo
        if(phoneNumber.startsWith("150")){
            return true;
        }
        return false;
    }
}

上述代码中,15行,处理欠费方法handleArrear首先判断当前用户是否为公司用户,如果是则在自己的处理范围,对其进行处理;否则将请求交由后继处理器处理。17行,如果在处理范围内,则向公司财务部发送催款邮件。30行判断用户是否为公司用户的方法isCompanyUser为演示方法,这里给出的规则是所有以150开头的号码都是公司用户,否则不是。
4.4 VipPersonalUserArrearHandler
VipPersonalUserArrearHandler是VIP个人用户欠费处理器,派生于ArrearHandler类。对应于职责链模式的参与者,VipPersonalUserArrearHandler是具体处理器ConcreteHandler。下面的代码给出了VipPersonalUserArrearHandler的声明。

package demo.designpattern.chainofresponsibility;

/**
 * VIP个人用户欠费处理器
 * Created by LiMingzi on 2017/7/28.
 */
public class VipPersonalUserArrearHandler extends ArrearHandler{
    /**
     * 处理欠费
     *
     * @param phoneNumber    电话号码
     * @param amountInArrear 欠费金额
     */
    @Override
    public void handleArrear(String phoneNumber, double amountInArrear) {
        if(isVip(phoneNumber)&&amountInArrear<1000){
            System.out.println("向用户发送催款短信,欠费号码:"+phoneNumber+",欠费金额:"+amountInArrear);
        }else{
            if(nextHandler!=null) {
                nextHandler.handleArrear(phoneNumber, amountInArrear);
            }
        }
    }

    /**
     * 是否为VIP用户
     * @param phoneNumber 电话号码
     * @return 是否为VIP用户
     */
    private boolean isVip(String phoneNumber){
        // demo
        if(phoneNumber.endsWith("888")){
            return true;
        }
        return false;
    }
}

上述代码中,15行,处理欠费方法handleArrear首先判断当前用户是否为VIP且欠费小于1000元,如果是则在自己的处理范围内,否则将请求交由后继处理器处理。17行,如果在处理范围内,向用户发送催款短息。30行判断用户是否为VIP的方法isVip为演示方法,这里给出的规则是所有以888结尾的号码都是VIP用户,否则不是。
4.5 PersonalUserArrearHandler
PersonalUserArrearHandler是个人用户欠费处理器,派生于ArrearHandler类。对应于职责链模式的参与者,PersonalUserArrearHandler是具体处理器ConcreteHandler。下面的代码给出了PersonalUserArrearHandler的声明。

package demo.designpattern.chainofresponsibility;

/**
 * 个人用户欠费处理器
 * Created by LiMingzi on 2017/7/28.
 */
public class PersonalUserArrearHandler extends ArrearHandler{
    /**
     * 处理欠费
     *
     * @param phoneNumber    电话号码
     * @param amountInArrear 欠费金额
     */
    @Override
    public  void handleArrear(String phoneNumber, double amountInArrear) {
        if(amountInArrear<100){
            System.out.println("向用户发送催款短信,欠费号码:"+phoneNumber+",欠费金额:"+amountInArrear);
        }else{
            System.out.println("向用户发送停机通知短信,欠费号码:"+phoneNumber+",欠费金额:"+amountInArrear);
            System.out.println("将号码:"+phoneNumber+"停机");
        }
    }
}

上述代码中,16行,如果用户欠费小于100元则发送催款短信,否则发送停机通知短信并停机。值得注意的是,该处理方法并未判断处理范围,也不会向后继处理器传递请求。即其作为末节点使用。如果在此段代码中加入一个处理范围判断,则将暴露职责链的另一个缺点,即无法保证请求一定被处理。这些都是在使用职责链模式时需要特殊注意的。
4.6 ArrearMgmt
ArrearMgmt是欠费管理类,处理所有用户欠费事件。对应于职责链模式的参与者,ArrearMgmt是客户Client。下面的代码给出了ArrearMgmt的声明。

package demo.designpattern.chainofresponsibility;

import java.util.HashMap;
import java.util.Map;

/**
 * 欠费管理
 * Created by LiMingzi on 2017/7/28.
 */
public class ArrearMgmt {
    /**
     * 欠费处理器
     */
    private ArrearHandler arrearHandler;

    /**
     * 构造方法
     */
    public ArrearMgmt() {
        arrearHandler = new CompanyUserArrearHandler();
        // vip用户欠费处理器
        ArrearHandler vipPersonalUserArearHandler = new VipPersonalUserArrearHandler();
        arrearHandler.setNextHandler(vipPersonalUserArearHandler);
        // 个人用户欠费处理器
        ArrearHandler persionalUserArrearHandler = new PersonalUserArrearHandler();
        vipPersonalUserArearHandler.setNextHandler(persionalUserArrearHandler);
    }

    /**
     * 获取欠费用户集合,demo
     * @return 欠费用户字典,key为电话号码,value为欠费金额
     */
    private Map getArrearUsers(){
        // 欠费用户字典
        Map arrearUsers = new HashMap<>();
        // 公司用户
        arrearUsers.put("15012354584",1200.0d);
        // VIP用户
        arrearUsers.put("13754567888",1100.0d);
        // VIP用户
        arrearUsers.put("13024524888",980.0d);
        // 个人用户
        arrearUsers.put("13154521475",120d);
        // 个人用户
        arrearUsers.put("13545751124",40.0d);
        return arrearUsers;
    }

    /**
     * 处理欠费
     */
    public void handleArrears(){
        // 欠费用户字典
        Map arrearUsers = getArrearUsers();
        for (Map.Entry arrearUserEntry : arrearUsers.entrySet()) {
            arrearHandler.handleArrear(arrearUserEntry.getKey(),arrearUserEntry.getValue());
        }
    }
}

上述代码中,14行,arrearHandler是欠费处理器对象,它在构造方法中被初始化。20-26行构建arrearHandler的过程也是构建整个职责链的过程。56行,在遍历所有欠费用户后,使用统一的处理器对象对欠费事件进行处理。33行,获取欠费用户集合方法getArrearUsers为演示方法,包含了可能出现的各种用户类型。
4.7 测试代码
为了测试本文中的代码,我们可以编写如下测试代码。从测试代码的输出可以很容易看到不同类型的用户欠费事件被不同的处理器处理。

    /**
     * 责任链测试
     */
    public static void chainOfResponsibilityTest(){
        // 欠费管理类对象
        ArrearMgmt arrearMgmt = new ArrearMgmt();
        arrearMgmt.handleArrears();
    }

编译运行后,得到如下测试结果:
向用户发送催款短信,欠费号码:13024524888,欠费金额:980.0
向用户发送停机通知短信,欠费号码:13754567888,欠费金额:1100.0
将号码:13754567888停机
向公司财务部发送催款邮件,欠费号码:15012354584,欠费金额:1200.0
向用户发送停机通知短信,欠费号码:13154521475,欠费金额:120.0
将号码:13154521475停机
向用户发送催款短信,欠费号码:13545751124,欠费金额:40.0

你可能感兴趣的:(算法与程序设计,设计模式,java,架构设计,设计模式讲解与代码实践)