基本介绍
模板方法模式 (Template Method Pattern) 也叫模板模式, 它在一个抽象类中公开定义了执行它的方法的模板, 它的字类可以按需重写方法实现, 但调用将以抽象类中定义的方式进行.
简单来说, 模板方法模式定义一个操作中的算法的骨架, 将一些步骤延迟到子类中, 使得子类可以不改变一个算法的结构, 就能重新定义该算法的某些特定步骤
模式结构
AbstractClass: 抽象类, 类中实现了模板方法, 定义了算法的骨架
ConcreteClass: 实现类, 继承抽象类, 重写其中的抽象方法
举例说明
编写一个制作豆浆的程序
制作豆浆的流程: 选材(黄豆) → 添加配料 → 浸泡 → 磨豆浆
要求: 通过添加不同的配料, 可以制作出不同口味的豆浆(除了添加配料不同, 其它步骤是相同的)
1, 定义一个抽象类, BaseSoyMilk: 豆浆类
- public abstract class BaseSoyMilk {
- /**
- * 模板方法, 制作豆浆的流程
- * 声明为 final, 防止子类重写
- */
- protected final void make() {
- select();
- addOther();
- soak();
- grind();
- }
- private void select() {
- System.out.println("选择上好的黄豆");
- }
- protected abstract void addOther();
- private void soak() {
- System.out.println("浸泡原材料");
- }
- private void grind() {
- System.out.println("研磨成豆浆");
- }
- }
2, 创建子类, PeanutSoyMilk: 花生豆浆
- public class PeanutSoyMilk extends BaseSoyMilk {
- @Override
- protected void addOther() {
- System.out.println("添加花生");
- }
- }
RedBeanSoyMilk: 红豆豆浆
- public class RedBeanSoyMilk extends BaseSoyMilk {
- @Override
- protected void addOther() {
- System.out.println("添加红豆");
- }
- }
3, 创建测试类: Client
- public class Client {
- @Test
- public void test() {
- BaseSoyMilk peanutSoyMilk = new PeanutSoyMilk();
- peanutSoyMilk.make();
- System.out.println("****************");
- BaseSoyMilk redBeanSoyMilk = new RedBeanSoyMilk();
- redBeanSoyMilk.make();
- }
- }
4, 运行结果
选择上好的黄豆
添加花生
浸泡原材料
研磨成豆浆
************
选择上好的黄豆
添加红豆
浸泡原材料
研磨成豆浆
钩子方法
在模板方法模式的抽象类中, 我们可以定义一个方法, 它默认不做任何事, 子类可以视情况来决定是否重写它, 该方法称为「钩子」.
依然以上面制作豆浆的例子来说明, 如果我们什么配料都不想加, 制作纯豆浆, 可以使用钩子方法对其改造.
1, 为 BaseSoyMilk 类添加一个方法 isAdd 判断是否添加其它材料
- public abstract class BaseSoyMilk {
- /**
- * 模板方法, 制作豆浆的流程
- * 声明为 final, 防止子类重写
- */
- protected final void make() {
- select();
- if(isAdd()){
- addOther();
- }
- soak();
- grind();
- }
- private void select() {
- System.out.println("选择上好的黄豆");
- }
- protected abstract void addOther();
- private void soak() {
- System.out.println("浸泡原材料");
- }
- private void grind() {
- System.out.println("研磨成豆浆");
- }
- protected boolean isAdd(){
- return true;
- }
- }
2, 创建一个子类 PureSoyMilk: 纯豆浆
- public class PureSoyMilk extends BaseSoyMilk {
- @Override
- protected void addOther() {
- }
- @Override
- protected boolean isAdd() {
- return false;
- }
- }
3, 测试
- @Test
- public void test2() {
- BaseSoyMilk pureSoyMilk = new PureSoyMilk();
- pureSoyMilk.make();
- }
4, 运行结果(现在就没有添加其它材料的步骤了)
选择上好的黄豆
浸泡原材料
研磨成豆浆
模式分析
优点
算法只存在于父类中, 易修改
实现了代码的复用性, 父类的一些方法直接被子类使用
既统一了算法, 也保证了很大的灵活性
缺点
每一个不同的实现都需要一个子类来实现, 导致类的数量增加, 是系统更庞大
注意事项
一般模板方法要加上 final 修饰符, 防止子类重写
使用场景
当我们要完成某个过程, 该过程有一系列步骤, 而且这些步骤基本相同, 只有个别步骤的实现可能不同, 可以考虑使用模板方法模式
在 Spring 源码中的应用
模板方法模式在 Spring IoC 容器初始化的时候有所应用, 我们看一下 AbstractApplicationContext 中的 refresh 方法, 它就是一个模板方法, 里面调用了一系列方法, 有以实现的具体方法, 有未实现的抽象方法, 也有空的钩子方法
- public void refresh() throws BeansException, IllegalStateException {
- synchronized (this.startupShutdownMonitor) {
- prepareRefresh();
- // 此方法内部调用了两个抽象方法 refreshBeanFactory()和 getBeanFactory()
- // 具体要取哪种 beanFactory 的控制权交给了子类
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
- prepareBeanFactory(beanFactory);
- try {
- // 钩子方法
- postProcessBeanFactory(beanFactory);
- invokeBeanFactoryPostProcessors(beanFactory);
- registerBeanPostProcessors(beanFactory);
- initMessageSource();
- initApplicationEventMulticaster();
- // 钩子方法
- onRefresh();
- registerListeners();
- finishBeanFactoryInitialization(beanFactory);
- finishRefresh();
- }
- catch (BeansException ex) {
- if (logger.isWarnEnabled()) {
- logger.warn("Exception encountered during context initialization -" +
- "cancelling refresh attempt:" + ex);
- }
- destroyBeans();
- cancelRefresh(ex);
- throw ex;
- }
- finally {
- resetCommonCaches();
- }
- }
- }
部分结构类图如下
来源: https://www.cnblogs.com/songjilong/p/12762088.html