参考:《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();
}
}
测试结果
2019-07-28 14:40:29,367 INFO - =====「张三」开始填写简历=====
2019-07-28 14:40:29,371 INFO - -----基本信息如下-----
2019-07-28 14:40:29,371 INFO - 基本情况填写开始:
2019-07-28 14:40:29,371 INFO - 「张三」开始填写姓名...
2019-07-28 14:40:29,371 INFO - 「张三」开始填写性别...
2019-07-28 14:40:29,372 INFO - 「张三」开始填写出生日期...
2019-07-28 14:40:29,372 INFO - 「张三」开始填写籍贯...
2019-07-28 14:40:29,372 INFO - 「张三」开始填写政治身份...
2019-07-28 14:40:29,372 INFO - -----教育背景如下-----
2019-07-28 14:40:29,372 INFO - 教育背景要求填写本科以上教育经历。
2019-07-28 14:40:29,372 INFO - 「张三」教育背景填写开始:
2019-07-28 14:40:29,373 INFO - 「张三」填写了本科阶段的求学经历...
2019-07-28 14:40:29,373 INFO - 「张三」填写了研究生阶段的求学经历...
2019-07-28 14:40:29,373 INFO - 「张三」教育背景填写完成。
2019-07-28 14:40:29,373 INFO - -----项目经历如下-----
2019-07-28 14:40:29,373 INFO - 项目经验要求控制在5条以内。
2019-07-28 14:40:29,373 INFO - 「张三」家庭成员填写开始:
2019-07-28 14:40:29,375 INFO - 「张三」填写了第「1」条项目经验...
2019-07-28 14:40:29,376 INFO - 「张三」填写了第「2」条项目经验...
2019-07-28 14:40:29,376 INFO - 「张三」项目经验填写完成。
2019-07-28 14:40:29,376 INFO - -----自我总结如下-----
2019-07-28 14:40:29,376 INFO - 个人总结要求在20~100字内。
2019-07-28 14:40:29,376 INFO - 「张三」个人总结填写开始:
2019-07-28 14:40:29,376 INFO - 「张三」填写了「31」个字...
2019-07-28 14:40:29,377 INFO - 「张三」个人总结填写完成。
2019-07-28 14:40:29,377 INFO - ==================================
2019-07-28 14:40:29,377 INFO - =====「李四」开始填写简历=====
2019-07-28 14:40:29,378 INFO - -----基本信息如下-----
2019-07-28 14:40:29,378 INFO - 基本情况填写开始:
2019-07-28 14:40:29,378 INFO - 「李四」开始填写姓名...
2019-07-28 14:40:29,378 INFO - 「李四」开始填写性别...
2019-07-28 14:40:29,378 INFO - 「李四」开始填写出生日期...
2019-07-28 14:40:29,378 INFO - 「李四」开始填写籍贯...
2019-07-28 14:40:29,378 INFO - 「李四」开始填写政治身份...
2019-07-28 14:40:29,379 INFO - 「李四」开始填写现居地...
2019-07-28 14:40:29,379 INFO - 「李四」开始填写工作年限...
2019-07-28 14:40:29,379 INFO - 「李四」开始填写是否已婚...
2019-07-28 14:40:29,379 INFO - -----教育背景如下-----
2019-07-28 14:40:29,379 INFO - 教育背景要求填写本科以上教育经历。
2019-07-28 14:40:29,379 INFO - 「李四」教育背景填写开始:
2019-07-28 14:40:29,379 INFO - 「李四」教育背景填写完成。
2019-07-28 14:40:29,379 INFO - -----家庭成员如下-----
2019-07-28 14:40:29,379 INFO - 家庭成员要求填写父母、兄弟姐妹和儿女的情况。
2019-07-28 14:40:29,379 INFO - 「李四」家庭成员填写开始:
2019-07-28 14:40:29,379 INFO - 「李四」填写了父母的基本情况...
2019-07-28 14:40:29,380 INFO - 「李四」家庭成员填写完成。
2019-07-28 14:40:29,380 INFO - -----项目经历如下-----
2019-07-28 14:40:29,380 INFO - 项目经验要求控制在5条以内。
2019-07-28 14:40:29,380 INFO - 「李四」家庭成员填写开始:
2019-07-28 14:40:29,404 INFO - 「李四」填写了第「1」条项目经验...
2019-07-28 14:40:29,405 INFO - 「李四」项目经验填写完成。
2019-07-28 14:40:29,405 INFO - -----自我总结如下-----
2019-07-28 14:40:29,405 INFO - 个人总结要求在20~100字内。
2019-07-28 14:40:29,405 INFO - 「李四」个人总结填写开始:
2019-07-28 14:40:29,405 INFO - 「李四」填写了「73」个字...
2019-07-28 14:40:29,405 INFO - 「李四」个人总结填写完成。
2019-07-28 14:40:29,405 INFO - -----其他如下-----
2019-07-28 14:40:29,405 INFO - 「李四」开始填写兴趣爱好...
3.模板方法模式与外观模式
两种模式的定义:
- 模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
- 外观模式:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
模板方法模式和外观模式很相似,都是封装方法,不同存在以下几点:
- 模板方法模式是一种
行为型
设计模式,侧重于将抽象父类中定义的算法模板在子类中延迟实现。 - 外观模式是一种
结构型
模式,侧重于为一组接口提供一个统一的外观。 - 模板方法模式侧重于封装的是同类对象的多个方法;外观模式侧重于封装的是多类对象的多个方法。
4.总结
最后以UML类图来总结本文的简历模板
场景以及模板方法模式
。
转载:https://blog.csdn.net/hanchao5272/article/details/97614786
查看评论