设计模式——模板方法模式

一、定义与简单实现

1、定义

  • 模板方法是一个定义在父类中的方法
  • 在模板方法中会顺序调用多个定义在父类中的其他方法,而这些方法有可能只是抽象方法
  • 模板方法保证了抽象方法的执行顺序,这些抽象方法由子类实现,并且子类不允许覆写模板方法

2、UML类图

 

模板方法模式与工厂方法模式的UML类图实现都是父类定义抽象方法,然后将具体实现延迟到子类,但还是有区别的

  • 模板方法模式是行为型设计模式,关注的是对象之间交流,可以是一个没有返回值的方法。
  • 工厂方法模式是创建型设计模式,关注的是对象的创建,必须返回一个创建好的对象。

模板方法模式中的设计原则:

  • 封装变化(抽象方法)
  • 依赖抽象,不依赖具体类
  • 对扩展开放,对修改关闭

3、简单代码实现

public interface TemplateService {
    void templateMethod();
}

public abstract class AbstractTemplateService implements TemplateService {
    @Override
    public void templateMethod() {
        //模板方法中的钩子方法isDoSomething1,子类可以改变方法执行顺序
        if(isDoSomething1()){
            doSomething1();
        }
        doSomething2();
        doSomething3();
    }

    protected boolean isDoSomething1(){
        return true;
    }

    protected void doSomething1(){
        System.out.println("something1 start");
    }

    /**
     * 子类不必实现,可以是空方法
     */
    protected void doSomething2(){

    }

    protected abstract void doSomething3();

}

public class ATemplateServiceImp extends AbstractTemplateService {

    @Override
    protected void doSomething3() {
        System.out.println("I am A");
    }
}

public class BTemplateServiceImp extends AbstractTemplateService {

    @Override
    protected boolean isDoSomething1() {
        return false;
    }

    @Override
    protected void doSomething2() {
        System.out.println("I am B");
    }

    @Override
    protected void doSomething3() {
        //empty
    }
}

public class Main {
    public static void main(String[] args) {
        TemplateService template = new ATemplateServiceImp();
        template.templateMethod();
        template = new BTemplateServiceImp();
        template.templateMethod();
    }
}

二、框架中的模板方法模式

模板方法在成熟的框架中用到的地方很多,最常见的就是SpringIOC容器的初始化

1、springIOC容器初始化

AbstractApplicationContext是一个抽象类,是SpringIOC容器类的超类。

它的refresh()方法就是一个模板方法,各种各样的springIOC容器都是根据这个模板方法初始化的。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // ② IOC初始化前的装备(配置环境参数、创建监听器、事件容器)
            prepareRefresh();

            // ③ 这里可以分为两类:
            // GenericApplicationContext: 仅仅是控制beanfactory不能重复refresh
            // AbstractRefreshableApplicationContext:允许重复refresh,销毁就beanfactory,创建新beanfactory并且重新扫描生成beanDefinitionMap容器。

            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // ④ 设置beanfactory的一些属性(bean的类加载器、忽略接口、BeanPostProcessor、环境参数单例注册到beanfactory单例容器中)
            prepareBeanFactory(beanFactory);

            try {
                // ⑤空方法,留由子类实现。
                //例如注册servlet相关的忽略接口、beanPostProcessor、各作用域生成bean的bean工厂
                //注册servlet的一些单例(servletContext/servletConfig/contextparameters/contextAttributes)到beanfactory的单例容器中
                postProcessBeanFactory(beanFactory);

                // ⑥beanFactoryPostProcessor排序并依次调用
                // beanFactoryPostProcessor:beanfactory的后置处理器,可以理解为一个beanfactory的拦截器(实例化后需要执行的自定义操作)
                // 例如:beanfactory初始化完成后,修改忽略接口、甚至可以对特定的beandefinition做修改
                invokeBeanFactoryPostProcessors(beanFactory);

                // ⑦BeanPostProcessors排序并依次注册到beanfactory的beanpostProcessor容器中
                // beanPostProcessors:bean实例化的处理器,可以理解为一个bean的拦截器(实例化前+实例化后需要执行自定义操作)
                // 例如:bean单例化前,修改beandefinition的属性。
                //实例化后DI,
                //拦截getbean()拦截返回一个代理类bean
                registerBeanPostProcessors(beanFactory);

                // ⑧初始化国际化文件,支持国际化
                initMessageSource();

                // ⑨初始化时间监听器并注册到beanfactory的单例容器中
                initApplicationEventMulticaster();

                // ⑩空方法,子类实现,初始化一些自定义bean并注册到beanfactory的单例容器中
                //  例如:themeSource,支持主题切换
                onRefresh();

                // ⑪注册个中监听器到beanfactory指定容器中
                registerListeners();

                // ⑫实例化不需要延迟加载的所有单例类型的bean(scope = singleton)
                finishBeanFactoryInitialization(beanFactory);

                // ⑬容器初始化完成,触发各种事件监控,ApplicationListener.onApplicationEvent()的执行时机(dubbo注册就是在这里实现的)
                // 例如:beanfactory的生命周期监控
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // ⑭ 容器初始化失败,销毁所有已实例化的bean
                destroyBeans();

                // ⑮ 设置active = false
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // ⑯ 清空公共的反射缓存
                resetCommonCaches();
            }
        }
    }  

2、JDK的ThreadPoolExecutor

线程池ThreadPoolExecutor的工作线程执行时,拓展了一个执行前,执行后方法

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

protected void beforeExecute(Thread t, Runnable r) { }

protected void afterExecute(Runnable r, Throwable t) { }

总结:模板方法模式特点:

在一个方法中定义一个算法的骨架(执行顺序),而将一些步骤延迟到子类中,模板方法还可以使得子类可以在不改变算法结构的情况下。重新定义算法中的某些步骤(钩子)。

强调的是方法执行顺序,还有延迟到子类实现。

posted on 2020-04-13 15:56  FFStayF  阅读(388)  评论(0编辑  收藏  举报