Java设计模式之责任链模式练习

Java中设计模式是为了解决问题,不要为了练习而强行在工程中应用,让原本100行代码就能实现的功能,写了1000行代码,对错不说,增加了代码的复杂度。下面一起看看责任链设计模式,进行练习。
责任链模式,一种行为设计模式,允许你将请求沿着处理者链进行发送,收到请求后,每个处理者均可以对请求进行处理,或将其传递给链上的下个处理者。
在这里插入图片描述
责任链模式使用的场景非常多,如审批流程,过滤器filter,在这些场景若不使用设计模式,那么当需求有所改变时,就会使得代码臃肿或难以维护。
实例
一个闯关游戏,进入下一关的条件时上一关的分数要高于XX分:

  • 3个关卡;
  • 若第一关得分大于等于80分则进入第二关;
  • 若第二关得分大于等于90分则进入第三关;

1、最初写法

public class FirstPassHandler {

    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        return 80;
    }

}
public class SecondPassHandler {

    public int handler(){
        System.out.println("第二关-->SecondPassHandler");
        return 90;
    }

}
public class ThirdPassHandler {

    public int handler(){
        System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");
        return 95;
    }

}

测试调用

	public static void main(String[] args) {
        //第一关
        FirstPassHandler firstPassHandler = new FirstPassHandler();
        //第二关
        SecondPassHandler secondPassHandler = new SecondPassHandler();
        //第三关
        ThirdPassHandler thirdPassHandler = new ThirdPassHandler();
        int firstScore = firstPassHandler.handler();
        //第一关的分数大于等于80则进入第二关
        if(firstScore >= 80){
            int secondScore = secondPassHandler.handler();
            //第二关的分数大于等于90则进入第二关
            if(secondScore >= 90){
                thirdPassHandler.handler();
            }
        }
    }

如果这个游戏有100关,那么调用的代码可能是这样子

		if (1关) {
            //
            if (2关) {
                // 
                if (3关) {
                    // 
                    if (4关) {
                        //
                        if (5关) {
                            //
                            ...
                        }
                    }
                }
            }
        }

这样子的代码不仅冗余,并且当跳转关卡时对代码的改动非常大,风险加大。

2、初步改造
通过链表将每一关连接起来,形成责任链的方式,第一关通过后进入第二关,第二个通过后进入第三关,这样调用就不需要多重if判断了。

public class FirstPassHandler {
    /**
     * 第一关的下一关是 第二关
     */
    private SecondPassHandler secondPassHandler;

    public void setSecondPassHandler(SecondPassHandler secondPassHandler) {
        this.secondPassHandler = secondPassHandler;
    }

    /**
     * 本关卡游戏得分
     * @return
     */
    private int play(){
        return 80;
    }

    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        if(play() >= 80){
            //分数>=80 并且存在下一关才进入下一关
            if(this.secondPassHandler != null){
                return this.secondPassHandler.handler();
            }
        }
        return 80;
    }
}
public class SecondPassHandler {

    /**
     * 第二关的下一关是 第三关
     */
    private ThirdPassHandler thirdPassHandler;

    public void setThirdPassHandler(ThirdPassHandler thirdPassHandler) {
        this.thirdPassHandler = thirdPassHandler;
    }

    /**
     * 本关卡游戏得分
     * @return
     */
    private int play(){
        return 90;
    }

    public int handler(){
        System.out.println("第二关-->SecondPassHandler");
        if(play() >= 90){
            //分数>=90 并且存在下一关才进入下一关
            if(this.thirdPassHandler != null){
                return this.thirdPassHandler.handler();
            }
        }
        return 90;
    }
}
public class ThirdPassHandler {

    /**
     * 本关卡游戏得分
     * @return
     */
    private int play(){
        return 95;
    }

    /**
     * 这是最后一关,因此没有下一关
     */
    public int handler(){
        System.out.println("第三关-->ThirdPassHandler,这是最后一关啦");
        return play();
    }
}

测试调用

	public static void main(String[] args) {
        //第一关
        FirstPassHandler firstPassHandler = new FirstPassHandler();
        //第二关
        SecondPassHandler secondPassHandler = new SecondPassHandler();
        //第三关
        ThirdPassHandler thirdPassHandler = new ThirdPassHandler();
        //第一关的下一关是第二关
        firstPassHandler.setSecondPassHandler(secondPassHandler);
        //第二关的下一关是第三关
        secondPassHandler.setThirdPassHandler(thirdPassHandler);
        //说明:因为第三关是最后一关,因此没有下一关
        //开始调用第一关 每一个关卡是否进入下一关卡 在每个关卡中判断
        firstPassHandler.handler();
    }

虽然连接起来了,但每个关卡中都有下一关卡的成员变量,形成链很不方便,扩展性不好。

3、责任链改造
每个关卡中都有下一关卡的成员变量,且是不一样的,可以在关卡上抽象出一个父类或接口,然后每个具体的关卡去继承或实现。

  • 抽象处理者角色:定义一个请求处理的接口,包含抽象处理方法和一个后继连接;
  • 具体处理者角色:实现抽象处理者的处理方法,判断是否处理本次请求,若可以则处理,否则将该请求转给后继者;
  • 测试调用角色:创建处理链,并向链头的具体处理者对象提交请求,不必关心处理细节和请求的传递过程;
public abstract class AbstractHandler {

    /**
     * 下一关用当前抽象类来接收
     */
    protected AbstractHandler next;

    public void setNext(AbstractHandler next) {
        this.next = next;
    }

    public abstract int handler();
}
public class FirstPassHandler extends AbstractHandler{

    private int play(){
        return 80;
    }

    @Override
    public int handler(){
        System.out.println("第一关-->FirstPassHandler");
        int score = play();
        if(score >= 80){
            //分数>=80 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }
        return score;
    }
}
public class SecondPassHandler extends AbstractHandler{

    private int play(){
        return 90;
    }

    @Override
    public int handler(){
        System.out.println("第二关-->SecondPassHandler");
        int score = play();
        if(score >= 90){
            //分数>=90 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }
        return score;
    }
}
public class ThirdPassHandler extends AbstractHandler{

    private int play(){
        return 95;
    }

    @Override
    public int handler(){
        System.out.println("第三关-->ThirdPassHandler");
        int score = play();
        if(score >= 95){
            //分数>=95 并且存在下一关才进入下一关
            if(this.next != null){
                return this.next.handler();
            }
        }
        return score;
    }
}

测试调用

	public static void main(String[] args) {
        //第一关
        FirstPassHandler firstPassHandler = new FirstPassHandler();
        //第二关
        SecondPassHandler secondPassHandler = new SecondPassHandler();
        //第三关
        ThirdPassHandler thirdPassHandler = new ThirdPassHandler();
        // 和上面没有更改的客户端代码相比,只有这里的set方法发生变化,其他都是一样的
        //第一关的下一关是第二关
        firstPassHandler.setNext(secondPassHandler);
        //第二关的下一关是第三关
        secondPassHandler.setNext(thirdPassHandler);
        //说明:因为第三关是最后一关,因此没有下一关
        //从第一个关卡开始
        firstPassHandler.handler();

    }

4、责任链工厂改造
对于上面的请求链,可以把这个关系维护在配置文件或一个枚举类中。
上一个改造中的抽象类和实现类如上,增加业务链的实体、枚举、链工厂等。

public class PassEntity {

    private String name;

    private String conference;

    private Integer handlerId;

    private Integer preHandlerId;

    private Integer nextHandlerId;

    public PassEntity(String name, String conference, Integer handlerId, Integer preHandlerId, Integer nextHandlerId) {
        this.name = name;
        this.conference = conference;
        this.handlerId = handlerId;
        this.preHandlerId = preHandlerId;
        this.nextHandlerId = nextHandlerId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getConference() {
        return conference;
    }

    public void setConference(String conference) {
        this.conference = conference;
    }

    public Integer getHandlerId() {
        return handlerId;
    }

    public void setHandlerId(Integer handlerId) {
        this.handlerId = handlerId;
    }

    public Integer getPreHandlerId() {
        return preHandlerId;
    }

    public void setPreHandlerId(Integer preHandlerId) {
        this.preHandlerId = preHandlerId;
    }

    public Integer getNextHandlerId() {
        return nextHandlerId;
    }

    public void setNextHandlerId(Integer nextHandlerId) {
        this.nextHandlerId = nextHandlerId;
    }
}
public enum PassEnum {

    // 拦截者名称 全限定类名 handlerId preHandlerId nextHandlerId
    FIRST_HANDLER(new PassEntity("first过滤", "com.FirstPassHandler", 1, null, 2)),
    SECOND_HANDLER(new PassEntity("second过滤", "com.SecondPassHandler", 2, 1, 3)),
    THIRD_HANDLER(new PassEntity("third过滤", "com.ThirdPassHandler", 3, 2, null)),
    ;

    PassEntity passEntity;

    public PassEntity getPassEntity() {
        return passEntity;
    }

    PassEnum(PassEntity passEntity) {
        this.passEntity = passEntity;
    }
}
public interface Pass {

    /**
     * 根据 handlerId 获取配置项
     * @param handlerId
     * @return
     */
    PassEntity getPassEntity(Integer handlerId);

    /**
     * 获取第一个处理者
     * @return
     */
    PassEntity getFirstPassEntity();
}
public class PassImpl implements Pass {

    /**
     * 初始化,将枚举中配置的handler初始化到map中,方便获取
     */
    private static Map<Integer, PassEntity> passEntityMap = new HashMap<>();

    static {
        PassEnum[] values = PassEnum.values();
        for (PassEnum value : values) {
            PassEntity passEntity = value.getPassEntity();
            passEntityMap.put(passEntity.getHandlerId(), passEntity);
        }
    }

    @Override
    public PassEntity getPassEntity(Integer handlerId) {
        return passEntityMap.get(handlerId);
    }

    @Override
    public PassEntity getFirstPassEntity() {
        for (Map.Entry<Integer, PassEntity> entry : passEntityMap.entrySet()) {
            PassEntity value = entry.getValue();
            //  没有上一个handler的就是第一个
            if (value.getPreHandlerId() == null) {
                return value;
            }
        }
        return null;
    }
}

工厂,根据枚举类动态形成一条调用链。

public class PassEnumHandlerFactory {

    private static Pass pass = new PassImpl();

    /**
     * 提供静态方法,获取第一个handler
     * @return
     */
    public static AbstractPassHandler getFirstPassHandler() {
        PassEntity firstPassEntity = pass.getFirstPassEntity();
        AbstractPassHandler firstAbstractPassHandler = newPassHandler(firstPassEntity);
        if (firstAbstractPassHandler == null) {
            return null;
        }
        PassEntity tempPassEntity = firstPassEntity;
        Integer nextHandlerId = null;
        AbstractPassHandler tempAbstractPassHandler = firstAbstractPassHandler;
        // 迭代遍历所有handler,以及将它们链接起来
        while ((nextHandlerId = tempPassEntity.getNextHandlerId()) != null) {
            PassEntity passEntity = pass.getPassEntity(nextHandlerId);
            AbstractPassHandler abstractPassHandler = newPassHandler(passEntity);
            tempAbstractPassHandler.setNext(abstractPassHandler);
            tempAbstractPassHandler = abstractPassHandler;
            tempPassEntity = passEntity;
        }
        // 返回第一个handler
        return firstAbstractPassHandler;
    }

    /**
     * 反射实体化具体的处理者
     * @param firstPassEntity
     * @return
     */
    private static AbstractPassHandler newPassHandler(PassEntity firstPassEntity) {
        // 获取全限定类名
        String className = firstPassEntity.getConference();
        try {
            // 根据全限定类名,加载并初始化该类,即会初始化该类的静态段
            Class<?> clazz = Class.forName(className);
            return (AbstractPassHandler) clazz.newInstance();
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
        return null;
    }

}

测试调用

	public static void main(String[] args) {
        AbstractPassHandler firstPassHandler = PassEnumHandlerFactory.getFirstPassHandler();
        firstPassHandler.handler();
    }

责任链模式还需深入理解其应用场景,应用于工程中解决实际问题才是关键,努力吧,少年。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值