当前位置 博文首页 > 韩超的博客 (hanchao5272):设计模式-模板方法模式-以简历模板为

    韩超的博客 (hanchao5272):设计模式-模板方法模式-以简历模板为

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

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

    参考:《HeadFirst设计模式》


    1.关于模板方法模式

    模板方法(template method)模式是一种行为型设计模式。

    模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

    本文以简历模板为场景来学习模板方法模式

    • 为了方便填写简历,简历都有模板。
    • 简历模板:基本信息、教育背景、家庭成员、项目经历、自我总结、其他。
    • 有些简历,例如某些大型国企的面试简历,需要填写家庭成员;有些不需要,例如互联网企业的面试简历。
    • 简历模板一般是通用的,可以对模板进行自定义,例如:基本信息中新增一些信息。

    2.实现方式:模板方法模式

    这个模式比较简单,直接进行设计模式编码。

    无论是为互联网企业提供的普通简历模板,还是为国企提供的特殊面试模板,他们都是一种简历模板。

    模板抽象:简历模板:AbstractResume

    AbstractResume作为抽象的简历模板类,主要提供以下编码:

    • 定义了简历填写fillIn()这个算法的骨架。如此,简历模板的实现类,都必须按照这个算法实现简历填写过程。
    • 实现了部分算法步骤,如fillInBasic()等,因为这些步骤可复用;未实现部分算法步骤,如fillInOther(),因为这个步骤难以预估。
    • 定义了若干算法步骤开关,如boolean fillInFamily等,因为有些步骤是可控的。
    /**
     * <p></P>
     *
     * @author hanchao
     */
    @Slf4j
    @NoArgsConstructor
    @RequiredArgsConstructor
    @AllArgsConstructor
    public abstract class AbstractResume {
        /**
         * 姓名
         */
        @Getter
        @NonNull
        private String name;
    
        /**
         * 是否填写家庭成员
         */
        private boolean fillInFamily = false;
    
        /**
         * 是否填写其他
         */
        private boolean fillInOther = false;
    
        /**
         * 填写简历 这里定义了算法骨架
         */
        public final void fillIn() {
            log.info("=====「{}」开始填写简历=====", name);
    
            //基本信息
            log.info("-----基本信息如下-----");
            fillInBasic();
    
            //教育背景
            log.info("-----教育背景如下-----");
            fillInEducation();
    
            //家庭成员
            if (fillInFamily) {
                log.info("-----家庭成员如下-----");
                fillInFamily();
            }
    
            //项目经历
            log.info("-----项目经历如下-----");
            fillInProject();
    
            //自我总结
            log.info("-----自我总结如下-----");
            fillInSummary();
    
            //其他
            if (fillInOther) {
                log.info("-----其他如下-----");
                fillInOther();
            }
        }
    
        /**
         * 填写基本情况
         */
        protected void fillInBasic() {
            log.info("基本情况填写开始:");
            log.info("「{}」开始填写姓名...", name);
            log.info("「{}」开始填写性别...", name);
            log.info("「{}」开始填写出生日期...", name);
            log.info("「{}」开始填写籍贯...", name);
            log.info("「{}」开始填写政治身份...", name);
        }
    
        /**
         * 填写教育背景
         */
        protected void fillInEducation() {
            log.info("教育背景要求填写本科以上教育经历。");
            log.info("「{}」教育背景填写开始:", name);
            if (RandomUtils.nextBoolean()) {
                log.info("「{}」填写了本科阶段的求学经历...", name);
                if (RandomUtils.nextBoolean()) {
                    log.info("「{}」填写了研究生阶段的求学经历...", name);
                    if (RandomUtils.nextBoolean()) {
                        log.info("「{}」填写了博士阶段的求学经历...", name);
                    }
                }
            }
            log.info("「{}」教育背景填写完成。", name);
        }
    
        /**
         * 填写家庭成员
         */
        protected void fillInFamily() {
            log.info("家庭成员要求填写父母、兄弟姐妹和儿女的情况。");
            log.info("「{}」家庭成员填写开始:", name);
            if (RandomUtils.nextBoolean()) {
                log.info("「{}」填写了父母的基本情况...", name);
            }
            if (RandomUtils.nextBoolean()) {
                log.info("「{}」填写了兄弟姐妹的基本情况...", name);
            }
            if (RandomUtils.nextBoolean()) {
                log.info("「{}」填写了儿女的基本情况...", name);
            }
            log.info("「{}」家庭成员填写完成。", name);
        }
    
        /**
         * 填写项目经验
         */
        protected void fillInProject() {
            log.info("项目经验要求控制在5条以内。");
            log.info("「{}」家庭成员填写开始:", name);
            for (int i = 0; i < RandomUtils.nextInt(2, 8) && i < 5; i++) {
                log.info("「{}」填写了第「{}」条项目经验...", name, 1 + i);
            }
            log.info("「{}」项目经验填写完成。", name);
        }
    
        /**
         * 填写个人总结
         */
        protected void fillInSummary() {
            log.info("个人总结要求在20~100字内。");
            log.info("「{}」个人总结填写开始:", name);
            log.info("「{}」填写了「{}」个字...", name, RandomUtils.nextInt(20, 100));
            log.info("「{}」个人总结填写完成。", name);
        }
    
        /**
         * 其他
         */
        protected void fillInOther(){
            //do nothing
        }
    }
    

    模板实现:普通简历模板:CustomResume

    • 普通的简历模板,无需显示家庭成员和其他,所以通过构造函数将两个开关关闭。
    /**
     * <p>普通简历模板: 无需显示家庭成员和其他</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class CustomResume extends AbstractResume {
        public CustomResume(@NonNull String name) {
            super(name, false, false);
        }
    }
    

    模板实现:特殊简历模板:

    • 特殊的简历模板,需要显示家庭成员和其他,所以通过构造函数将两个开关打开。
    • 特殊的简历模板,其基本情况步骤要更加复杂,所以自己重写了这个方法。
    • 抽象类中,未定义兴趣爱好的填写,故而重写fillInOther(),将相关逻辑放在此处。
    /**
     * <p>一种特殊简历模板:需要填写家庭成员和其他,并且自定义了基本信息</P>
     *
     * @author hanchao
     */
    @Slf4j
    public class SpecialResume extends AbstractResume {
        public SpecialResume(@NonNull String name) {
            super(name, true, true);
        }
    
        /**
         * 填写基本情况 这里是将算法的实现延迟到子类中
         */
        @Override
        protected void fillInBasic() {
            super.fillInBasic();
            log.info("「{}」开始填写现居地...", super.getName());
            log.info("「{}」开始填写工作年限...", super.getName());
            log.info("「{}」开始填写是否已婚...", super.getName());
        }
    
        /**
         * 其他 这里是将算法的实现延迟到子类中
         */
        @Override
        protected void fillInOther() {
            log.info("「{}」开始填写兴趣爱好...", super.getName());
        }
    }
    

    测试代码:

    @Slf4j
    public class TemplateMethodDemo {
        public static void main(String[] args) {
            //普通简历模板的填写
            AbstractResume resume = new CustomResume("张三");
            resume.fillIn();
    
            log.info("==================================");
    
            //特殊建立模板的填写
            resume = new SpecialResume("李四");
            resume.fillIn