当前位置 博文首页 > 韩超的博客 (hanchao5272):设计模式-责任链模式-以多轮面试为例

    韩超的博客 (hanchao5272):设计模式-责任链模式-以多轮面试为例

    作者:[db:作者] 时间:2021-09-05 16:13

    超级链接: Java常用设计模式的实例学习系列-绪论

    参考:《HeadFirst设计模式》


    1.关于责任链模式

    责任链(Chain of Responsibility)模式是一种行为型模式。

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

    本文以多轮面试为场景来学习责任链模式

    • 招聘流程:笔试面试ExamInterview、技术面试TechnicalInterview、HR面试HRInterview。
    • 每轮面试的内容各不相同,如果不能达到本轮面试标准,则被淘汰。
    • 需求变化:有可能添加CEO面试CEOInterview,减少笔试等等;针对不同的求职者可能有不同的面试安排。

    2.实现方式1: 所有面试环节放在一个类中

    • 所有的面试环节都放在一个类中。
    • 针对不同的面试者,提供不同的面试方法。

    超级面试类:SuperInterview“

    /**
     * <p>超级面试类</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class SuperInterview {
        /**
         * 针对普通求职者的面试过程
         */
        public static String customInterview(String name) {
            //笔试
            log.info("[{}]开始参加笔试", name);
            log.info("此轮笔试共计10道选择题,5到机试题,共计100分,答题时间60分钟。");
            Integer score = RandomUtils.nextInt(40, 100);
            if (score >= 60) {
                log.info("[{}]笔试得分为{},通过了笔试。", name, score);
            } else {
                log.info("[{}]笔试得分为{},未通过了笔试。", name, score);
                return "面试结果:未通过笔试";
            }
            log.info("[{}]进入下一轮面试。", name);
            log.info("--------------------------------");
    
            //技术面试
            log.info("[{}]开始参加技术面试", name);
            log.info("技术面试官先问了一些基础知识");
            Boolean pass = RandomUtils.nextBoolean();
            if (pass) {
                log.info("[{}]基础知识回答得很完美,继续技术面试。", name);
            } else {
                log.info("[{}]基础知识掌握的很差,未通过了笔试。", name);
                return "面试结果:未通过技术面试";
            }
            log.info("技术面试官又问了一些高级知识");
            pass = RandomUtils.nextBoolean();
            if (pass) {
                log.info("[{}]高级知识回答得马马虎虎,继续技术面试。", name);
            } else {
                log.info("[{}]高级知识简直是不懂装通,未通过了笔试。", name);
                return "面试结果:未通过技术面试";
            }
    
            log.info("[{}]进入下一轮面试。", name);
            log.info("--------------------------------");
    
            //HR面试
            log.info("[{}]开始参加HR笔试", name);
            log.info("HR先聊了聊公司的背景、现状、前景...");
            log.info("[{}]反映很满意。");
            log.info("HR开始谈工资。");
            Integer percent = RandomUtils.nextInt(0, 50);
            if (percent <= 25) {
                log.info("[{}]期望工资涨幅为{}%,在HR承受范围内,通过了面试。", name, percent);
            } else {
                log.info("[{}]期望工资涨幅为{}%,超出HR承受范围内,未通过了面试。", name, percent);
                return "面试结果:未通过HR面试";
            }
            log.info("[{}]进入下一轮面试。", name);
            log.info("--------------------------------");
    
            log.info("[{}]通过了所有面试,恭喜你!", name);
            return "通过了所有面试,恭喜你!";
        }
    
        /**
         * 针对高级求职者的面试过程
         */
        public static String advancedInterview(String name) {
            //技术面试
            log.info("[{}]开始参加技术面试", name);
            log.info("技术面试官先问了一些基础知识");
            Boolean pass = RandomUtils.nextBoolean();
            if (pass) {
                log.info("[{}]基础知识回答得很完美,继续技术面试。", name);
            } else {
                log.info("[{}]基础知识掌握的很差,未通过了笔试。", name);
                return "面试结果:未通过技术面试";
            }
            log.info("技术面试官又问了一些高级知识");
            pass = RandomUtils.nextBoolean();
            if (pass) {
                log.info("[{}]高级知识回答得马马虎虎,继续技术面试。", name);
            } else {
                log.info("[{}]高级知识简直是不懂装通,未通过了笔试。", name);
                return "面试结果:未通过技术面试";
            }
    
            log.info("[{}]进入下一轮面试。", name);
            log.info("--------------------------------");
    
            //HR面试
            log.info("[{}]开始参加HR笔试", name);
            log.info("HR先聊了聊公司的背景、现状、前景...");
            log.info("[{}]反映很满意。");
            log.info("HR开始谈工资。");
            Integer percent = RandomUtils.nextInt(0, 50);
            if (percent <= 25) {
                log.info("[{}]期望工资涨幅为{}%,在HR承受范围内,通过了面试。", name, percent);
            } else {
                log.info("[{}]期望工资涨幅为{}%,超出HR承受范围内,未通过了面试。", name, percent);
                return "面试结果:未通过HR面试";
            }
            log.info("[{}]进入下一轮面试。", name);
            log.info("--------------------------------");
    
            log.info("[{}]通过了所有面试,恭喜你!", name);
            return "通过了所有面试,恭喜你!";
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 5; i++) {
                SuperInterview.customInterview("求职者" + i);
                System.out.println();
            }
        }
    }
    

    缺点:

    • 扩展性差:如果增减面试环节,则必然会修改SuperInterview,违背设计原则对修改关闭,对扩展放开
    • 复用性低:如果针对不同的人群实施不同的面试安排,则需要写两个SuperInterview,很多代码重复,代码复用低。
    • 灵活性差:HR请假了,所以HR面试环节取消一段时间,这时需要注释掉所有HR面试代码;再HR请假结束之后,需要恢复所有HR面试代码。灵活性很差。

    3.实现方式2:责任链模式

    首先,无论是笔试、技术面试还是HR面试,都是一轮面试,所以,抽象出面试抽象类:Interview

    /**
     * <p>一轮面试</P>
     *
     * @author hanchao
     */
    @AllArgsConstructor
    public abstract class AbstractInterview {
        /**
         * 下一轮面试
         */
        @Getter
        private AbstractInterview interview;
    
        /**
         * 面试
         */
        public abstract String interview(String name);
    }
    

    然后,既然这个模式称之为责任,什么是

    可以拿链表进行理解,一轮面试相当于链表的一个节点。

    那么,链表节点的结构时怎样的呢,大体如下:

    public class Node {
        /**
         * 数据
         */
        private String data;
        /**
         * 下一个节点
         */
        private Node next;//指向下一个节点
       	//...
    }
    

    很容易想到,责任链模式的每个节点也是这种结构:包含下一个节点的引用。

    根据上述分析,编写以下代码。

    责任节点:笔试:ExamInterview

    /**
     * <p>笔试</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class ExamInterview extends AbstractInterview {
    
        public ExamInterview(AbstractInterview interview) {
            super(interview);
        }
    
        /**
         * 面试
         */
        @Override
        public String interview(String name) {
            //笔试
            log.info("[{}]开始参加笔试", name);
            log.info("此轮笔试共计10道选择题,5到机试题,共计100分,答题时间60分钟。");
            Integer score = RandomUtils.nextInt(40, 100);
            if (score >= 60) {
                log.info("[{}]笔试得分为{},通过了笔试。", name, score);
            } else {
                log.info