设计模式-Template

438 阅读3分钟

行为型模式

模板方法模式定义一个操作中算法的骨架,而将一些步骤延迟到子类中实现,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

组成

一个模板方法用一些抽象的操作组成一个算法,而子类重定义这些操作以提供具体的行为,它的组成如下图所示:

模板方法组成

上图中各个组成的作用:

  • AbstractClass -- 抽象类

    把多个抽象方法组成一个算法模板(TemplateMethod);

  • ConcreteClass -- 具体的子类

    实现 AbstractClass 中定义的抽象方法,实现模板方法中特定步骤。

模板方法模式是一种代码复用的基本技术,它通过子类的继承来扩展父类的行为。它导致了一个反向的控制结构:子类不会去调用父类的方法,而是父类调用子类的方法。子类的调用权限在由父类控制,是IoC的一种表现。

应用场景

在以下场景,可以使用模板方法模式:

  • 业务需求大体流程相同,只是在一些具体步骤上不同;
  • 各个子类中公共的行为应该被提取出来并集中到一个公共父类中,避免代码重复;
  • 算法可以分为“变化”与“不变”的两个部分,不变的部分由抽象父类实现,变化的部分由子类实现;

示例代码

Spring 框架中 AbstractApplicationContext 类的 refresh() 方法实现了 IoC 容器初始化过程中的主要步骤,相当于一个模板,代码如下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            onRefresh();

            // Check for listener beans and register them.
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            finishRefresh();
        }

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

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

该模板方法中的一些方法,比如 prepareRefreshpostProcessBeanFactoryonRefresh 可以由子类重写,实现各自逻辑。

优点和缺点

1、用抽象父类封装了“不变"的部分,子类扩展”变化“的部分;

2、提取了公共代码,降低了代码重复、便有维护;

3、注意事项:模板方法要加上 final 关键词修饰,避免被子类误修改;

小结

在使用模板方法模式时,关键是要确定其中”不变“和”变化“的部分,不变的部分作为步骤,变的部分作为其中的某个步骤由子类来实现。

同样是”通过继承来扩展“,模板方法模式 与 策略模式的区别在于:

  • 模板方法模式关注的是在一个模板方法中自定义一部分具体步骤;
  • 策略模式关注的是改变整个模板方法(提供多种策略);