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


    概念

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

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

    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中的增删改查
    设计模式总结

  • 相关阅读:
    判断表字段是否存在default约束
    在Eclipse mars 4.5.2 中安装spring 插件 spring tool suite
    MySql (mysql-5.6.37) 在Windows的安装及使用
    在CentOS7.2中搭建Tomcat9 并启用http/2 协议
    CentOS 7.2 中 Kafka,Zookeeper的单机部署,伪分布式部署以及真正的分布式部署
    博客歇菜后的总结
    通过WiFi连接手机(device), 出去数据线的烦恼
    Android Studio 使用三星 Note4 真机调试
    在Mac team 工作的那段日子里(一)
    又到年底了,没钱回家咋办?
  • 原文地址:https://www.cnblogs.com/z00377750/p/9396187.html
Copyright © 2020-2023  润新知