趣解设计模式之《小王看病记》

〇、小故事

小王最近参与了公司一个大项目,工作很忙,经常加班熬夜,满负荷工作了2个月后,项目终于如期上线,并且客户反馈也特别的好。老板很开心,知道大家为这个项目付出了很多,所以给全组同事都放了1个星期的假。

小王在项目期间也经常因为饮食不规范而导致胃疼,最近也越来越严重了。所以他就想趁着这个假期时间去医院检查一下身体

他来到医院的挂号处,首先缴费挂号,挂了一个检查胃部的诊室。

小王按照挂号信息,来到了诊室,医生简单的询问了一下他的病情,然后给他开了几个需要检查的单子

小王带着医生开具的检查单,就在医院的收费处排队等待着缴费

缴费完毕后,小王就按照医生开的检查项目进行了身体检查......

那么从上面小王的一系列看病流程我们可以发现,这是一系列的处理过程,跟链条一样,即:

挂号------>开检查单------>缴费------>检查------>......

那么对于类似这种的业务逻辑,我们就可以使用一种设计模式来处理,即今天要介绍的------责任链模式

一、模式定义

责任链模式Chain of Responsibility Pattern

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

二、模式类图

下面我们再举一个例子,一家公司收到了好多的电子邮件,其中大致分为四类:

CEO处理 】公司粉丝发来的邮件。

法律部门处理诽谤公司产品的邮件。

业务部门处理 】要求业务合作的邮件。

直接丢弃 】其他垃圾邮件。

这里需要CEO先查阅邮件处理,然后再由法务部处理,随后是业务部处理,最后是垃圾邮件执行废弃。根据以上的描述,我们首先需要邮件实体类 Email,和用于区分不同处理方式的邮件类型 EmailType。对于所有处理者,我们首先创建一个抽象的处理器类AbstractProcessor,再创建四个处理器的实现类,分别是CEO处理器 CeoProcessor法务部门处理器 LawProcessor业务部门处理器 BusinessProcessor垃圾邮件处理器 GarbageProcessor。具体类关系如下图所示:

三、模式实现

创建邮件实体类Email.java

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Email {
    // 邮件类型
    private int type;

    // 邮件内容
    private String content;
}

创建邮件类型枚举类EmailType.java

java 复制代码
public enum EmailType {
    FANS_EMAIL(1, "粉丝邮件"),
    SLANDER_EMAIL(2, "诽谤邮件"),
    COOPERATE_EMAIL(3, "业务合作邮件"),
    GARBAGE_EMAIL(99, "垃圾邮件");

    public int type;

    public String remark;

    EmailType(int type, String remark) {
        this.type = type;
        this.remark = remark;
    }
}

创建抽象处理类AbstractProcessor.java

java 复制代码
public abstract class AbstractProcessor {

    // 责任链中下一个处理节点
    private AbstractProcessor nextProcessor;

    // 返回的处理结果
    private String result;

    public final String handleMessage(List<Email> emails) {
        List<Email> filterEmails =
                emails.stream().filter(email -> email.getType() == this.emailType()).collect(Collectors.toList());
        result = this.execute(filterEmails);
        if (this.nextProcessor == null) {
            return result;
        }
        return this.nextProcessor.handleMessage(emails);
    }

    // 设置责任链的下一个处理器
    public void setNextProcessor(AbstractProcessor processor) {
        this.nextProcessor = processor;
    }

    // 获得当前Processor可以处理的邮件类型
    protected abstract int emailType();

    // 具体处理方法
    protected abstract String execute(List<Email> emails);
}

创建CEO处理类CeoProcessor.java

java 复制代码
public class CeoProcessor extends AbstractProcessor {
    @Override
    protected int emailType() {
        return EmailType.FANS_EMAIL.type; // 处理粉丝来的邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------CEO开始处理邮件-------");
            emails.stream().forEach(email -> 
                                    System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}

创建法律部门处理类LawProcessor.java

java 复制代码
public class LawProcessor extends AbstractProcessor {

    @Override
    protected int emailType() {
        return EmailType.SLANDER_EMAIL.type; // 处理诽谤类型的邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------法律部门开始处理邮件-------");
            emails.stream().forEach(email -> 
                                    System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}

创建业务部门处理类BusinessProcessor.java

java 复制代码
public class BusinessProcessor extends AbstractProcessor {

    @Override
    protected int emailType() {
        return EmailType.COOPERATE_EMAIL.type; // 处理合作类型的邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------业务部门开始处理邮件-------");
            emails.stream().forEach(email -> 
                                    System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}

创建垃圾邮件处理类GarbageProcessor.java

java 复制代码
public class GarbageProcessor extends AbstractProcessor {

    @Override
    protected int emailType() {
        return EmailType.GARBAGE_EMAIL.type; // 处理垃圾类型邮件
    }

    @Override
    protected String execute(List<Email> emails) {
        if (CollectionUtils.isNotEmpty(emails)) {
            System.out.println("-------垃圾开始处理邮件-------");
            emails.stream().forEach(email -> 
                                    System.out.println(email.getContent()));
        }
        return "任务执行完毕!";
    }
}

创建责任链模式测试类ChainTest.java

java 复制代码
public class ChainTest {
    // 初始化待处理邮件
    private static List<Email> emails = Lists.newArrayList(
        	new Email(EmailType.FANS_EMAIL.type, "我是粉丝A"),
            new Email(EmailType.COOPERATE_EMAIL.type, "我要找你们合作"),
            new Email(EmailType.GARBAGE_EMAIL.type, "我是垃圾邮件"),
            new Email(EmailType.FANS_EMAIL.type, "我是粉丝B"));

    public static void main(String[] args) {
        // 初始化处理类
        AbstractProcessor ceoProcessor = new CeoProcessor();
        AbstractProcessor lawProcessor = new LawProcessor();
        AbstractProcessor businessProcessor = new BusinessProcessor();
        AbstractProcessor garbageProcessor = new GarbageProcessor();

        // 设置责任链条
        ceoProcessor.setNextProcessor(lawProcessor);
        lawProcessor.setNextProcessor(businessProcessor);
        businessProcessor.setNextProcessor(garbageProcessor);

        // 开始处理邮件
        ceoProcessor.handleMessage(emails);
    }
}

执行后的结果

java 复制代码
-------CEO开始处理邮件-------
我是粉丝A
我是粉丝B
-------业务部门开始处理邮件-------
我要找你们合作
-------垃圾开始处理邮件-------
我是垃圾邮件

Process finished with exit code 0

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享

更多技术干货,欢迎大家关注公众号"爪哇缪斯" ~ \(^o^)/ ~ 「干货分享,每天更新」

相关推荐
Victor35612 分钟前
MongoDB(87)如何使用GridFS?
后端
Victor35615 分钟前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁32 分钟前
单线程 Redis 的高性能之道
redis·后端
GetcharZp37 分钟前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴2 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友2 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算
IT_陈寒3 小时前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
前端Hardy4 小时前
前端必看!LocalStorage这么用,再也不踩坑(多框架通用,直接复制)
前端·javascript·面试
前端Hardy4 小时前
前端必看!前端路由守卫这么写,再也不担心权限混乱(Vue/React通用)
前端·javascript·面试
Soofjan4 小时前
Go 内存回收-GC 源码1-触发与阶段
后端