设计模式——Spring IoC中用到的模板方法模式

基本概念

什么是模板方法(Template method):父类定义了骨架(调用哪些方法及顺序),某些特定方法由子类实现。

最大的好处:代码复用,减少重复代码。除了子类要实现的特定方法,其他方法及方法调用顺序都在父类中预先写好了。

所以父类模板方法中有两类方法:

1、共同的方法:所有子类都会用到的代码

2、不同的方法:子类要覆盖的方法,分为两种:

  A、抽象方法:父类中的是抽象方法,子类必须覆盖

  B、钩子方法:父类中是一个空方法,子类继承了默认也是空的

注:为什么叫钩子,子类可以通过这个钩子(方法),控制父类,因为这个钩子实际是父类的方法(空方法)!

模板方法模式,和现实中的模板很像,一个文档的模板通常是一个完成了部分内容的表格(表格模板就像一个模板方法),每个人都会拿到表格的副本(具体的实现类)进行某些项的填写,每个人都可以对指定项(抽象方法或钩子方法)进行填写,表格中的必填项就像抽象方法必须实现,表格中的非必填项就是钩子方法。当然只是比喻和实际情况不完全一样。

UML图

Java代码展示

下面的代码展示了,模板方法模式在Java代码中通常是怎样的:

1、先定义一个接口,主要是定义了模板方法

public interface TemplateInterface {
    public void execute();
}

2、抽象类实现了接口,主要是实现了模板方法的逻辑,模板方法中调用了自己的逻辑方法,还有最重要的钩子方法和抽象方法

public abstract class TemplateAbstractClass implements TemplateInterface{
    /**模板方法*/
    @Override
    public void execute() {
        preDoSomething();
        abstractMethod();
        hookMethod();
        afterDoSomething();
    }
    private void preDoSomething(){
        System.out.println("before do some thing in abstract class");
    }
    private void afterDoSomething(){
        System.out.println("after do some thing in abstract class");
    }
    /**抽象方法*/
    public abstract void abstractMethod();
    /**钩子方法*/
    public void hookMethod(){
    }
}

3、两个子类,One只实现了抽象方法,Two实现了抽象方法并覆盖了钩子方法

public class SubClassOne extends TemplateAbstractClass{
    /**抽象方法*/
    @Override
    public void abstractMethod() {
        System.out.println("do another thing by subClassOne");
    }
}
public class SubClassTwo extends TemplateAbstractClass{
    /**抽象方法*/
    @Override
    public void abstractMethod() {
        System.out.println("do another thing by subClassTwo");
    }
    /**钩子方法*/
    @Override
    public void hookMethod() {
        System.out.println("hook method in subClassTwo");
    }
}

Spring中的模板方法模式

Spring中几乎所有的扩展,都使用了模板方法模式,JdbcTemplate中应该很多,不过还没学到那里,这里说下IoC部分的模板方法模式!

注:貌似在业务系统中很少看到,是开发者的编码能力问题还是对实际情况不适用,但是在框架中很多,Java IO、Spring、Hibernate等,可能是作为一个框架来说考虑更多的是扩展问题!

下面的代码展示了Spring IOC容器初始化时运用到的模板方法模式。(截取部分关键代码)

1、首先定义一个接口ConfigurableApplicationContext,声明模板方法refresh

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
  /**声明了一个模板方法*/
  void refresh() throws BeansException, IllegalStateException;
}

2、抽象类AbstractApplicationContext实现了接口,主要实现了模板方法refresh(这个方法很重要,是各种IOC容器初始化的入口)的逻辑

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {

   /**模板方法的具体实现*/
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.
            prepareRefresh();

        //注意这个方法是,里面调用了两个抽象方法refreshBeanFactory、getBeanFactory
            // 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.
                destroyBeans();
                // Reset ‘active‘ flag.
                cancelRefresh(ex);
                // Propagate exception to caller.
                throw ex;
            }
        }
    }

这里最主要有一个抽象方法obtainFreshBeanFactory、两个钩子方法postProcessBeanFactory和onRefresh,看看他们在类中的定义

两个钩子方法:

    protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    }
    protected void onRefresh() throws BeansException {
        // For subclasses: do nothing by default.
    }

再看看获取Spring容器的抽象方法:

  /**其实他内部只调用了两个抽象方法**/
  protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }
  protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
  public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

具体要取那种BeanFactory容器的决定权交给了子类!

3、具体实现的子类,实现了抽象方法getBeanFactory的子类有:

AbstractRefreshableApplicationContext:

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
        synchronized (this.beanFactoryMonitor) {
            if (this.beanFactory == null) {
                throw new IllegalStateException("BeanFactory not initialized or already closed - " +
                        "call ‘refresh‘ before accessing beans via the ApplicationContext");
            }
            //这里的this.beanFactory在另一个抽象方法refreshBeanFactory的设置的
            return this.beanFactory;
        }
    }
}    
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
    @Override
    public final ConfigurableListableBeanFactory getBeanFactory() {
    //同样这里的this.beanFactory在另一个抽象方法中设置
    return this.beanFactory;
    }
}

其实这里的差别还不是很大,我们可以看看另一个抽象方法refreshBeanFactory的实现,两个抽象方法的配合使用。

所以这里的UML是:

时间: 2024-10-12 02:24:26

设计模式——Spring IoC中用到的模板方法模式的相关文章

设计模式 ( 二十 ): Template method模板方法模式 -- 行为型

  1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关.例子1:银行业务办理流程在银行办理业务时,一般都包含几个基本固定步骤:取号排队->办理具体业务->对银行工作人员进行评分.取号取号排队和对银行工作人员进行评分业务逻辑是一样的.但是办理具体业务是个不相同的,具体业务可能取款.存款或者转账. 2.问题 如何保证架构逻辑的正常执行,而不被子类破坏 ? 3.

设计模式学习笔记之九:模板方法模式

现在我家里有一台铃木的小车锋驭和一台铃木的摩托车风暴1000,我要想把这两种类型的车都先跑起来再停下来,有一些步骤,并且这些步骤是有先后顺序的,那就是: 1. 打开车门 2. 启动发动机 3. 挂档 4. 走起 5. 刹车 6. 停车 OO设计原则之一就是分离可变和不变的部分并把可变的部分封装起来,我们来看一下以上两种类型的车,哪些步骤的实现是一样的,哪些是可变的.我们把不变的部分提取出来并放到超类中让所有子类共享其行为,同时我们把可变部分的具体实现延迟到子类中,让子类来自行决定如何实现. 1.

《大话设计模式》ruby版代码:模板方法模式

需求: 学生抄题目,做题目 初始代码 # -*- encoding: utf-8 -*- #学生甲的试卷类 class TestPaperA def question1 puts '杨过得到,后来给了郭靖,炼成倚天剑,屠龙刀的玄铁可能是[] a.球墨铸铁 b.马口铁 c.高速合金钢 d.碳塑纤维 ' puts '答案:b' end def question2 puts '杨过.程英.陆无双铲除了情花,造成了[] a.使这种植物不再害人 b.使一种珍稀物种灭绝 c.破坏了那个生物圈的生态平衡 d.

大话设计模式C++实现-第10章-模板方法模式

一.UML图 二.概念 模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 三.说明 角色: (1)AbstractClass:是抽象类,其实也就是一个抽象模板,定义并实现了一个模板方法.这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的框架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现.顶级逻辑也有可能调用一些具体方法. (2)ConcreteClass:实现父类所定义的一个或多个抽象方法.每一

设计模式学习(十六) 模板方法模式

场景: -- 客户到银行办理业务 1:取号排队 2:办理具体现金/转账/企业/个人/理财业务 3: 给银行工作人员评分 模板方法介绍; -- 模板方法模式是编程中经常用到的模式,它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现.这样,新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤 核心: -- 处理某个流程的代码已经都具备,但是其中某个节点的代码暂时不能确定.因此,我们采用模板方法模式.将这个节点的代码实现转移给子类完成.即:处理步骤父类中定义好,具体实现延迟到子类

《大话设计模式》学习笔记7:模板方法模式

考题试卷示例: 1.试卷父类: public class TestPaper { public void TestQuestion1() { Console.WriteLine("杨过是哪部小说中的人物?a.飞狐外传 b.天龙八部 c.射雕英雄传 d.笑傲江湖"); Console.WriteLine("答案:"+Answer1()); } public void TestQuestion2() { Console.WriteLine("令狐冲是哪部小说中

无处不在的模板方法模式

话说网上总结的设计模式都以单例,工厂,观察者等模式最多,但是我个人觉得真正无处不在的却是模板方法.曾经有一位微软的讲师说过如果你只想学一种设计模式,那就模板方法吧. 笔者曾经开发过一款安全软件,其中负责云扫描模块.当然扫描部分也不止只用在云查杀部分,例如附带的清理功能,保险箱扫描可保护的软件都会用到扫描文件功能.但是如果分开写几套扫描逻辑却实在不可取,于是当时我用了下面的设计: class IScanBase { public: BOOL ScanFile(CString strPath) {

重构机房收费系统之 模板方法模式

对于模板方法模式的使用,我懊悔自己用晚了,由于我们的机房收费收费系统有非常多窗口是差点儿一样的,假设我们不用模板方法模式,就会大大添加工作量,首先,我们须要反复的创建窗口,其次我们的代码量也会大大添加,就是复制.粘贴代码也是一件让人摒弃的事情,所以推出模板方法模式,用意就在降低代码反复,降低工作量,通过求同存异的思想来实现.以下看一下我在组合查询中用到的模板方法模式: 首先,创建父窗口,父窗口的创建就是普通的winform,我们知道组合查询这块儿一共同拥有四个窗口是大同小异的:学生上机状态查看.

设计模式@第16章:模板方法模式

第16章:模板方法模式 一.豆浆制作问题 编写制作豆浆的程序,说明如下: 制作豆浆的流程 选材--->添加配料--->浸泡--->放到豆浆机打碎 通过添加不同的配料,可以制作出不同口味的豆浆 选材.浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的 请使用 模板方法模式 完成 (说明:因为模板方法模式,比较简单,很容易就想到这个方案,因此就直接使用, 不再使用传统的方案来引出模板方法模式 ) 二.模板方法模式基本介绍 基本介绍 模板方法模式(Template Method P