深入理解23种设计模式(12) -- 模版方法模式

在这里插入图片描述

介绍

  1. 模版方法模式 (Template Method Pattern) , 又叫模版模式(Template Pattern),在一个抽象类公开定义类执行它的方法的模版。它的子类可以按需要重写方法实现,但调用将以抽象类中定义但方式进行。
  2. 模版方法模式定义类一个操作中但算法但骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法但结构,就可以重定义该算法但某些特征
  3. 模版方法模式属于行为型模式 在这里插入图片描述 原理图解析:
  • AbstractClass:抽象类,类中实现类模版方法(template),定义了算法但骨架,具体子类需要去实现其他的抽象方法
  • ConcreteClass :子类,完成算法中特定子类的步骤

案列:

豆浆制作问题

  1. 制作豆浆的流程 选材 ---> 添加配料 ---> 浸泡 ---> 放到豆浆机打碎
  2. 通过替阿甲不同的配料,可以制作出不同口味的豆浆
  3. 选材、浸泡的放到豆浆机这几个步骤 对于美中口味的豆浆都是一样的

编写模版类

public abstract class SoyaMilk {

    /**
     * 模版方法 final不让子类覆盖
     */
    final void make(){
        select();
        addCondiments();
        soak();
        beat();
    }

    /**
     * 选材料
     */
    private void select(){
        System.out.println("第一步:选择好的新鲜的豆浆");
    }

    /**
     * 添加不同的材料
     */
    abstract void addCondiments();


    /**
     * 浸泡
     */
    private void soak(){
        System.out.println("第三部,开始浸泡");
    }

    /**
     * 放到豆浆机
     */
    private void beat(){
        System.out.println("第四步:放到豆浆机");
    }


}

子类实现

public class BlackBeanSoyaMilk extends SoyaMilk{
    @Override
    void addCondiments() {
        System.out.println("黑豆");
    }
}
public class PeanutSoyaMilk extends SoyaMilk{

    @Override
    void addCondiments() {
        System.out.println("花生");
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        System.out.println("---制作黑豆豆浆---");
        SoyaMilk soyaMilk = new BlackBeanSoyaMilk();
        soyaMilk.make();


        System.out.println("---制作花生豆浆---");
        SoyaMilk soyaMilk1 = new PeanutSoyaMilk();
        soyaMilk1.make();
    }
}

在这里插入图片描述

模版方法模式的钩子方法

  1. 在模版方法模式的父类中,我妈可以定义一个方法,它默认不做任何事,子类可以看情况可不可以覆盖他,该方法称为钩子
public abstract class SoyaMilk {

    /**
     * 模版方法 final不让子类覆盖
     */
    final void make(){
        select();
        if(customerWantCondiments()){
            addCondiments();
        }
        soak();
        beat();
    }

    /**
     * 选材料
     */
    private void select(){
        System.out.println("第一步:选择好的新鲜的豆浆");
    }

    /**
     * 添加不同的材料
     */
    abstract void addCondiments();


    /**
     * 浸泡
     */
    private void soak(){
        System.out.println("第三部,开始浸泡");
    }

    /**
     * 放到豆浆机
     */
    private void beat(){
        System.out.println("第四步:放到豆浆机");
    }


    /**
     * 钩子方法
     */
    boolean customerWantCondiments(){
        return true;
    }


}

实现钩子

public class PureSoyaMilk extends SoyaMilk{
    @Override
    void addCondiments() {
        System.out.println("不加东西");
    }

    @Override
    boolean customerWantCondiments() {
        return false;
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        System.out.println("---制作豆浆---");
        SoyaMilk soyaMilk2 = new PureSoyaMilk();
        soyaMilk2.make();
    }
}

在这里插入图片描述


Spring中的模板方法模式

Spring中几乎所有的扩展,都使用了模板方法模式,这里说下IoC部分的模板方法模式!


  1. 定义一个接口ConfigurableApplicationContext,声明模板方法refresh
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.context;

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {

    /**
     * 模版方法
     */
    void refresh() throws BeansException, IllegalStateException;

    
}

在这里插入图片描述

  1. 抽象类 抽象类AbstractApplicationContext实现了接口 。实现类refresh 方法 是各种IOC容器初始化的入口)的逻辑

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {


    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
        	//为刷新做好准备
            this.prepareRefresh();
            //方法如下,调用了了两个抽象方法refreshBeanFactory、getBeanFactory
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            //准备bean工厂
            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();
    }
  • 这里最主要有一个抽象方法obtainFreshBeanFactory、两个钩子方法postProcessBeanFactory和onRefresh,看看他们在类中的定义

两个钩子方法

protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }


protected void onRefresh() throws BeansException {
    }

我们查看 AbstractApplicationContext 实现类 在这里插入图片描述

AbstractRefreshableApplicationContext 子类 重写了 getBeanFactory()方法

	 public final ConfigurableListableBeanFactory getBeanFactory() {
	        DefaultListableBeanFactory beanFactory = this.beanFactory;
	        if (beanFactory == null) {
	            throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext");
	        } else {
	            return beanFactory;
	        }
	    }



	@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			this.beanFactory = beanFactory;
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

GenericApplicationContext 子类 重写了 getBeanFactory()方法

	private final DefaultListableBeanFactory beanFactory;


	@Override
	public final ConfigurableListableBeanFactory getBeanFactory() {
		return this.beanFactory;
	}



	@Override
	protected final void refreshBeanFactory() throws IllegalStateException {
		if (!this.refreshed.compareAndSet(false, true)) {
			throw new IllegalStateException(
					"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
		}
		this.beanFactory.setSerializationId(getId());
	}


github Demo地址 : ~~~传送门~~~

个人博客地址:http://blog.yanxiaolong.cn/

end
  • 作者:yxl(联系作者)
  • 发表时间:2021-02-21 12:22
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 转载声明:如果是转载栈主转载的文章,请附上原文链接
  • 公众号转载:请在文末添加作者公众号二维码(公众号二维码见右边,欢迎关注)
  • 评论