【设计模式】【行为型模式】模板模式

概念

模板模式定义了一个算法的步骤,并允许子类为一个或多个步骤提供其实践方式。让子类在不改变算法架构的情况下,重新定义算法中的某些步骤。

抽象摸板角色:(抽象父类)

  1. 定义了一个或多个抽象操作,以便让子类实现
  2. 定义并实现了一个摸板方法

具体摸板角色:(具体实现类)

  1. 实现父类所定义的一个或多个抽象方法
  2. 每一个抽象摸板角色都可以有任意多个具体摸板角色与之对应
  3. 每一个具体摸板角色都可以给出这些抽象方法的不同实现

模板方法模式就是基于继承的代码复用技术的。在模板方法模式中,我们可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中。也就是说我们需要声明一个抽象的父类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法让子类来实现剩余的逻辑,不同的子类可以以不同的方式来实现这些逻辑。所以模板方法的模板其实就是一个普通的方法,只不过这个方法是将算法实现的步骤封装起来的。

模式中的方法种类:

  1. 抽象模板角色里提供完整的方法,它完成了所有派生类都要用到的一些基本功能。
  2. 抽象模板角色里只提供空方法,把功能全部留给派生类去实现。
  3. 抽象模板角色里只包含某些操作的默认实现,派生类里可以重新定义这些方法的实现。
  4. 抽象模板角色里模板方法,他是一个调用抽象方法,钩子方法以及具体方法的各种组合。

实例

创建一个定义操作的 Game 抽象类,其中,模板方法设置为 final,这样它就不会被重写。Cricket 和 Football 是扩展了 Game 的实体类,它们重写了抽象类的方法。

TemplatePatternDemo,我们的演示类使用 Game 来演示模板模式的用法。

步骤 1

创建一个抽象类,它的模板方法被设置为 final。

Game.java

public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();

   //模板
   public final void play(){

      //初始化游戏
      initialize();

      //开始游戏
      startPlay();

      //结束游戏
      endPlay();
   }
}

步骤 2
创建扩展了上述类的实体类。

Cricket.java

public class Cricket extends Game {

   @Override
   void endPlay() {
      System.out.println("Cricket Game Finished!");
   }

   @Override
   void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }

   @Override
   void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}
Football.java

public class Football extends Game {

   @Override
   void endPlay() {
      System.out.println("Football Game Finished!");
   }

   @Override
   void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }

   @Override
   void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}

步骤 3
使用 Game 的模板方法 play() 来演示游戏的定义方式。

TemplatePatternDemo.java

public class TemplatePatternDemo {
   public static void main(String[] args) {

      Game game = new Cricket();
      game.play();
      System.out.println();
      game = new Football();
      game.play();      
   }
}

步骤 4
验证输出。

Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!

Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!

应用

在Spring中的AbstractApplicationContext的refresh方法中使用了模板模式。

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) {
                // Destroy already created singletons to avoid dangling resources.
                beanFactory.destroySingletons();

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

                // Propagate exception to caller.
                throw ex;
            }
        }
    }

AbstractApplicationContext类中的refresh定义好了代码逻辑骨架,obtainFreshBeanFactory()方法中调用了refreshBeanFactory();,该方法在AbstractApplicationContext中是抽象方法,需要在子类中具体实现。

//AbstractApplicationContext
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        if (logger.isInfoEnabled()) {
            logger.info("Bean factory for application context [" + getId() + "]: " +
                    ObjectUtils.identityToString(beanFactory));
        }
        if (logger.isDebugEnabled()) {
            logger.debug(beanFactory.getBeanDefinitionCount() + " beans defined in " + this);
        }

        return beanFactory;
    }
    
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
    

查看AbstractApplicationContext的子类

最终类是FileSystemXmlApplicationContext,方法的具体实现在AbstractRefreshableApplicationContext中可以找到。

//AbstractRefreshableApplicationContext
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException(
                    "I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
        }
    }

参考资料:
模板模式
使用模板方法设计模式、策略模式 处理DAO中的增删改查
设计模式总结

猜你喜欢

转载自www.cnblogs.com/z00377750/p/9396187.html