• 模板方法


    • 概述
    • UML类图
    • 代码栗子
    • Spring源码体现
    • 总结

    概述

    • 概述
      模板方法是一种行为设计模式,它在超类(抽象类)中定义算法的框架,但允许子类覆盖算法的特定步骤而无需更改其结构。

    • 作用

      1. 允许子类实现变化的行为(通过重写钩子方法)
      2. 避免了重复代码:算法的一般工作流程在抽象类的模板方法中实现一次,而子类中实现必要的变体。
      3. 控制允许专业化的点。如果子类只是简单地覆盖模板方法,则它们可以对工作流进行根本性和任意的更改。相反,通过仅覆盖钩子方法,仅可以更改工作流的某些特定细节,并且整个工作流保持不变。

    UML类图

    img

    代码栗子

    //动作类
    public interface Action {
        /**
         * 吃
         * @param name
         */
        void eat(String name) ;
    
    }
    
    //抽象模板类
    public abstract class AbstractDefaultAction implements Action {
        /**
         * 吃饭前的动作
         * 子类必须实现的方法
         */
        public abstract void before();
    
      //模板方法
        @Override
        public final void eat(String name) {
            before();
            System.out.println("吃饭吃的是:"+name);;
            after();
        }
    
        /**
         * 吃饭后的动作
         * 钩子方法
         */
        public  void after(){
            System.out.println("默认实现,洗手");
        }
    }
    
    public class LiSi extends AbstractDefaultAction {
        private  static String name ="李四";
    
        @Override
        public void before() {
            System.out.println(name+";吃饭前,不洗手");
    
        }
    
        @Override
        public void after() {
            System.out.println("吃完洗碗");
        }
    }
    
    public class ZhangSan extends AbstractDefaultAction {
        private  static String name ="张三";
    
        @Override
        public void before() {
            System.out.println(name+";吃饭前,洗手");
    
        }
    }
    
    • client
    public class Main {
        public static void main(String[] args) {
            Action  a = new ZhangSan() ;
            a.eat("香蕉");
            System.out.println("-----------分割线---------");
            Action  b = new LiSi() ;
            b.eat("苹果");
        }
    
    }
    
    • 运行效果

    img

    Spring源码体现

    使用IDEA 双击shift查找类,进入org.springframework.context.ConfigurableApplicationContext,找到refresh() 方法,找到他的实现类org.springframework.context.support.AbstractApplicationContext,它的实现方式就是一个模板方法,源码如下:

    @Override
    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();
                }
            }
        }
    

    根据这个refresh的方法注释可知,这就是Spring加载资源配置文件用的,规定了整个加载流程,但是放开了流程细节交由其子类实现

    总结

    • 多个子类有公有的方法,并且逻辑基本相同时。把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
    • 重构时,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。
  • 相关阅读:
    [FAQ] GitHub 开启二次验证之后,如何通过 https clone 项目 ?
    [FAQ] GoLand 需要手动开启代码补全吗 ?
    [FAQ] 夏玉米 按规则查询域名靠谱吗 ?
    [FAQ] Error: com.mysql.jdbc.Driver not loaded. :jdbc_driver_library
    [php-src] Php内核的有趣高频宏
    [php-src] Php扩展开发的琐碎注意点、细节
    [ELK] Docker 运行 Elastic Stack 支持 TLS 的两种简单方式
    [Contract] Solidity 生成随机数方案
    [MySQL] 导入数据库和表的两种方式
    [ELK] 生产环境中 Elasticsearch 的重要配置项
  • 原文地址:https://www.cnblogs.com/tanoak/p/11897851.html
Copyright © 2020-2023  润新知