【设计模式】模板方法模式

模板方法模式

在学习模板方法模式之前,我们先以一个生活中比较常见的例子来引入。

比如我们制作豆浆的时候,流程都是选材料—添加配料----浸泡----放到豆浆机中打碎。

我们通过添加不同的配料,就可以了制作出不同口味的豆浆。

其中 1 2 4部对于每个豆浆的制作过程都是一样的。这种情况下我们就很容易的想到模板方法。也可能你不知道这就是模板方法模式,但是你实际上已经在使用了。

一、模板方法模式基本介绍

  1. 模板方法模式又叫模板模式,在一个抽象类公开定义了执行他的方法的模板。他的子类可有按需要重写方法实现,但调用将以抽象类中定义的方式进行
  2. 简单来说,模板方法模式定义一个操作中的算法的骨架。而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以了重新定义该算法的某些特定步骤
  3. 这种设计模式属于行为型模式

二、模板方法模式的原理类图

在这里插入图片描述

说明:

  • AbstractClass抽象类,类中实现类模板方法,定义了算法的骨架,具体子类需要去实现其他的抽象方法
  • ConcreteClass实现抽象方法,以完成算法中特定子类的步骤
1.使用模板方法模式解决上述问题

在这里插入图片描述

  • 定义抽象类

    package com.slp.pattern.template;
    
    /**
     * @ClassName SoyaMilk
     * @Description 抽象类,表示豆浆
     * @Author sanglp
     * @Date 2020/8/26 8:17
     * @Version 1.0
     **/
    public abstract class SoyaMilk {
        //模板方法 make 模板方法可以做成final 不让子类去覆盖
        final void make(){
            select();
            if(customWantCondiments()){
                addCondiments();
            }
    
            soak();
            beat();
        }
    
        void select(){
            System.out.println("选择合适的材料");
        }
        //添加不同配料 抽象方法 子类具体实现
        abstract void addCondiments();
        //浸泡
        void soak(){
            System.out.println("开始浸泡 需要3小时");
        }
    
        void beat(){
            System.out.println("打豆浆");
        }
    }
    
  • 定义具体子类

    package com.slp.pattern.template;
    
    /**
     * @ClassName RedBeanSoyaMilk
     * @Description TODO
     * @Author sanglp
     * @Date 2020/8/26 8:23
     * @Version 1.0
     **/
    public class RedBeanSoyaMilk extends SoyaMilk{
        @Override
        void addCondiments() {
            System.out.println("加入上好的红豆");
        }
    }
    
    package com.slp.pattern.template;
    
    /**
     * @ClassName PeanutSoyalMilk
     * @Description TODO
     * @Author sanglp
     * @Date 2020/8/26 8:24
     * @Version 1.0
     **/
    public class PeanutSoyalMilk  extends SoyaMilk {
        @Override
        void addCondiments() {
            System.out.println("加入花生");
        }
    }
    
  • 客户端

    package com.slp.pattern.template;
    
    import com.slp.pattern.decorator.v1.Soy;
    
    /**
     * @ClassName Client
     * @Description TODO
     * @Author sanglp
     * @Date 2020/8/26 8:25
     * @Version 1.0
     **/
    public class Client {
        public static void main(String[] args) {
            System.out.println("制作红豆豆浆");
            SoyaMilk soyaMilk = new RedBeanSoyaMilk();
            soyaMilk.make();
            System.out.println("制作华生豆浆");
            SoyaMilk peanut = new PeanutSoyalMilk();
            peanut.make();
            System.out.println("制作纯豆浆");
            SoyaMilk pureMilk = new PureSoyalMilk();
            pureMilk.make();
    
           // ConfigurableApplicationContext
        }
    }
    
    package com.slp.pattern.template;
    
    /**
     * @ClassName PureSoyalMilk
     * @Description 钩子方法
     * @Author sanglp
     * @Date 2020/8/26 8:30
     * @Version 1.0
     **/
    public class PureSoyalMilk extends SoyaMilk {
    
        @Override
        void addCondiments() {
    
        }
    
        @Override
        boolean customWantCondiments() {
            return false;
        }
    }
    
2.模板方法模式的钩子方法
  • 在模板方法模式的父类中,我们可以定义一个方法,他默认不做任何事,子类可以视情况要不要覆盖它,这个方法被称为钩子
  • 比如上面的方法我们希望制作纯豆浆,这就可以使用钩子方法对上述代码进行修改
package com.slp.pattern.template;

/**
 * @ClassName SoyaMilk
 * @Description 抽象类,表示豆浆
 * @Author sanglp
 * @Date 2020/8/26 8:17
 * @Version 1.0
 **/
public abstract class SoyaMilk {
    //模板方法 make 模板方法可以做成final 不让子类去覆盖
    final void make(){
        select();
        if(customWantCondiments()){
            addCondiments();
        }

        soak();
        beat();
    }

    void select(){
        System.out.println("选择合适的材料");
    }
    //添加不同配料 抽象方法 子类具体实现
    abstract void addCondiments();
    //浸泡
    void soak(){
        System.out.println("开始浸泡 需要3小时");
    }

    void beat(){
        System.out.println("打豆浆");
    }

    //钩子方法 决定是否需要添加配料
    boolean customWantCondiments(){
        return true;
    }
}

三、模板方法模式在Spring框架中的应用

  • SpringIOC容器初始化的时候用到了模板方法模式
    在这里插入图片描述
void refresh() throws BeansException, IllegalStateException;
public void refresh() throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        this.prepareBeanFactory(beanFactory);

        try {
            this.postProcessBeanFactory(beanFactory);
            this.invokeBeanFactoryPostProcessors(beanFactory);
            this.registerBeanPostProcessors(beanFactory);
            this.initMessageSource();
            this.initApplicationEventMulticaster();
            this.onRefresh();
            this.registerListeners();
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();
        } catch (BeansException var9) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            this.destroyBeans();
            this.cancelRefresh(var9);
            throw var9;
        } finally {
            this.resetCommonCaches();
        }

    }
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    this.refreshBeanFactory();//抽象方法
    return this.getBeanFactory();//抽象方法
}
//钩子方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
//钩子方法
protected void onRefresh() throws BeansException {
}

在这里插入图片描述

四、模板方法模式的注意事项和细节

  1. 基本思想是:短发只存在于一个地方,也就是在父类中,容易修改,需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
  2. 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用
  3. 既统一了短发,也提供了很大的灵活性,父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现
  4. 该模式的不足之处:每个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
  5. 一般模板方法都加上final关键字,防止子类重写模板方法
  6. 模板方法的使用场景:当要完成某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不太,通常考虑用模板方法模式来处理
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值