责任链模式

责任链模式

高铁线路

在现实生活中,一个事件需要经过多个对象处理是很常见的场景。例如,采购审批流程、请假流程等。公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据需要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这无疑增加了难度。

那么有没有一种模式,只需要知道出发点,中间经过多少环节并不用用户关心,顺着流程就可以达到最终的结果。就好比搭高铁,只需要知道起点和终点即可,买票起点搭车到站下车,中间经过多少站点,每个站点停留了多久时间不用乘客关心,甚至可以睡觉。

查看源图像
高铁线路上的站点

要使用户无感中间站点,高铁线路工作者需要把每个站点预设好,并且把它串起来起来,让高铁顺滑跑下去。那么如何串起来呢,需要每个站记住下一个站就好,这样就可以索引着跑下去。

尝试使用一个抽象类来代表站台吧。

package com.skystep.设计模式.责任链模式;

public abstract class Station {
    // 标记下一个站
    protected Station next;

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

    public Station getNext() {
        return next;
    }
	// 模拟站点停留
    public abstract void stay();
}

OK,先建立一个叫做 “深圳北站” 的站点,作为起点站。

package com.skystep.设计模式.责任链模式;

import java.util.Objects;

public class ShenZhenNorthStation extends Station{
    @Override
    public void stay() {
        System.out.println("10s后列车从深圳北站出发..。");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (Objects.nonNull(next)) next.stay();
    }
}

OK,再建立一个叫做 “东莞虎门站” 的站点,作为中间站。

package com.skystep.设计模式.责任链模式;

import java.util.Objects;

public class DongGuanHuMenStation extends Station {
    @Override
    public void stay() {
        System.out.println("东莞虎门站到了,请下车的乘客下车..。");
        System.out.println("此站停留20s");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (Objects.nonNull(next)) next.stay();
    }
}

OK,再建立一个叫做 “广州南站” 的站点,作为终点站。

package com.skystep.设计模式.责任链模式;

import java.util.Objects;

public class GuangzhouSouthStation extends Station {
    @Override
    public void stay() {
        System.out.println("广州南站到了,该站是终点站,感谢搭乘.。");
        System.out.println("此站停留20s");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (Objects.nonNull(next)) next.stay();
    }
}
名叫深广线的线路

OK,是时候连接起一条高铁路线了,就叫“深广线”线吧。

package com.skystep.设计模式.责任链模式;

public class ShenZhen2GuangZhou {
    private final Station station;

    // 把站点一个个连起来
    public ShenZhen2GuangZhou() {
        ShenZhenNorthStation shenZhenNorthStation = new ShenZhenNorthStation();
        DongGuanHuMenStation dongGuanHuMenStation = new DongGuanHuMenStation();
        GuangzhouSouthStation guangzhouSouthStation = new GuangzhouSouthStation();
        shenZhenNorthStation.setNext(dongGuanHuMenStation);
        dongGuanHuMenStation.setNext(guangzhouSouthStation);
        station = shenZhenNorthStation;
    }
	// 跑起来
    public void run() {
        station.stay();
    }
}

那么写个客户端类,跑起来吧。

package com.skystep.设计模式.责任链模式;

public class Test {
    public static void main(String[] args) {
        ShenZhen2GuangZhou shenZhen2GuangZhou = new ShenZhen2GuangZhou();
        shenZhen2GuangZhou.run();
    }
}

高铁从深圳北站出发,途径东莞虎门站,最终到广州南站。

10s后列车从深圳北站出发..。
东莞虎门站到了,请下车的乘客下车..。
此站停留20s
广州南站到了,该站是终点站,感谢搭乘.。
此站停留20s

有了 ShenZhen2GuangZhou 这条链路,使用者将不再关系其内部实现了,不关心经过多少站点。反正可以从深圳到广州。对于高铁线路工作者来说,可以在这中间添加其他的站点,不影响每个站点原先的业务。此外每个站点还可以组合形成其他的线路。

查看源图像
回归模式

这种把处理环节抽象串联起来的模式叫做 “责任链模式”,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,因此职责链将请求的发送者和请求的处理者解耦了。换成人话,要从深圳到广州,使用 ShenZhen2GuangZhou 类就可以了,ShenZhen2GuangZhou 中已经做好每个站点的处理。“责任链模式” 是一种行为模式,常常被用作消息的的多道过滤处理。

责任链模式中,存在着两个重要角色:

  • Handler: 抽象处理者 相当于站台 Station ;
  • concreteHandler:具体的处理者是处理请求的具体角色,相当于 ShenZhenNorthStation、DongGuanHuMenStation。

责任链模式的类图如下:

image-20220412225949922
应用场景

责任链在实际业务中有很多应用,

  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定;
  • 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
  • 可动态指定一组对象处理请求;
深广线的线路优化
优化重复代码

在具体的处理者每个类都存在以下代码:

if (Objects.nonNull(next)) next.stay();

于是配合模板设计模式,把这个代码抽到抽象类中,

package com.skystep.设计模式.责任链模式;

import java.util.Objects;

public abstract class Station {
    protected Station next;

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

    public Station getNext() {
        return next;
    }

    // 子类必须重写
    protected void _stay() {
        throw new UnsupportedOperationException();
    }

    
    public void stay() {
        _stay();
        if (Objects.nonNull(next)) next._stay();
    }
}

对具体的处理者进行修改,

package com.skystep.设计模式.责任链模式;

import java.util.Objects;

public class DongGuanHuMenStation extends Station {
    @Override
    public void _stay() {
        System.out.println("东莞虎门站到了,请下车的乘客下车..。");
        System.out.println("此站停留20s");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
将返回值作为参数

如果需要将上次节点执行的结果作为下一个节点的参数,那么抽象处理类可以做以下调整。

package com.skystep.设计模式.责任链模式;

import java.util.Objects;

public abstract class Station {
    protected Station next;

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

    public Station getNext() {
        return next;
    }

    // 子类必须重写
    protected Object _stay(Object param) {
        throw new UnsupportedOperationException();
    }

    
    public void stay(Object param) {
        Object object = _stay(param);
        if (Objects.nonNull(next)) next._stay(object);
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k8DZDYoH-1656256417779)(https://img.mianfeiwendang.com/pic/82e75047cf194e3683307c46/1-810-jpg_6-1080-0-0-1080.jpg)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值