一篇博客读懂设计模式之---模板方法模式

设计模式之模板方法模式:

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

简而言之就是:父类定义了骨架(调用哪些方法及其顺序),某些特定的方法由具体的子类来实现。
所以呢?在父类模板方法中是有两类方法的:

  1. 共同的方法:所有子类都必须用到的方法,类似于定义了一个框架,通常不用abstract而是final来修饰,防止子类重写,像下面的play方法
  2. 不同的方法:子类需要重写或者覆盖的方法,这种方法也分为两种:
    1). 抽象方法:父类是抽象方法,子类必须实现的,如下面的startGame,endGame方法;
    2). 钩子方法:父类中是一个空方法,子类继承的时候默认也是空的,这个方法有什么用呢?子类可以通过这个方法来自定义自己的其他一些步骤和过程,从而达到控制父类的目的。

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

1. 创建抽象类Game:

public abstract  class Game {abstract void startGame();abstract void endGame();abstract void init();final void play(){init();startGame();endGame();}
}

2. 创建扩展了上述类的实体类:

public class FootballGame extends Game {@Overridevoid startGame() {System.out.println("start football");}@Overridevoid endGame() {System.out.println("end football");}@Overridevoid init() {System.out.println("init football");}
}
public class BasketballGame extends Game {@Overridevoid startGame() {System.out.println("start basketball");}@Overridevoid endGame() {System.out.println("end basketball");}@Overridevoid init() {System.out.println("init basketball");}
}

3. 使用测试类测试:

public class TemplMain {public static void main(String[] args) {Game game = new FootballGame();//这样如果你想要改变其他球类,只需要换成下面这种形式,其他不用改变//Game game = new BasketballGame();game.play();}
}

在这里插入图片描述

再升级一下,举另一个例子:

在这里插入图片描述
接口描述的是一种共性,一种动作action;
抽象类描述的是一个模板,一个特定的过程;
而子类则是可以根据自己的需要定制自己的过程。

不过,这样做的好处又是什么呢?

  1. 将族群进行隔离,像上面的图一样,我们可以将不同种类的人,美洲人,亚洲人进行隔离,而不互相影响;
  2. 可以将一些日志和共性的动作很好的分离,规范子类的动作。

其实我们在一些框架,如spring,mybatis等都可以看到模板方法模式的影子,下面简单举一下例子:
像mybatis的Executor接口:
在这里插入图片描述
你就可以很明显的看到这种模式:
在这里插入图片描述

spring中的模板方法模式:
在这里插入图片描述
spring模板方法我来摘抄一些重点给大家看看:
下面的代码展示了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 DefaultResourceLoaderimplements 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,看看他们在类中的定义
看看获取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;

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

AbstractRefreshableApplicationContext:

public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {@Overridepublic 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;}}
}

GenericApplicationContext:

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {@Overridepublic final ConfigurableListableBeanFactory getBeanFactory() {//同样这里的this.beanFactory在另一个抽象方法中设置        return this.beanFactory;}
}

在这里插入图片描述

大家有空可以自己进去看看里面的源码!里面真是高深莫测!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/558821.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一篇读懂--mybatis的缓存

一篇读懂–mybatis的缓存 MyBatis的缓存指的是缓存查询结果,当以后使用相同的sql语句、传入相同的参数进行查询时,可直接从mybatis本地缓存中获取查询结果,而不必查询数据库。 mybatis的缓存包括一级缓存、二级缓存,一级缓存默认…

Spring Boot————BeanCreationNotAllowedException异常分析

引言 在对数据库进行新增记录的JUnit测试时,抛出一个BeanCreationNotAllowedException异常: 异常分析与解决 异常信息太长,图片截不下,粘贴来看: Exception in thread "pool-2-thread-1" org.springframew…

一篇博客读懂设计模式之---委派模式

一篇博客读懂设计模式之—委派模式 委派模式可能大家听起来不太熟悉,但是在代码开发的时候却很好用,下面从几个方面来介绍一下 what:是什么? 委派模式:顾名思义,委托其他对象或者实例来帮我们完成任务&am…

Jackson快速入门

引言 上一篇博客《XML模板解析————Dom4j解析xml案例分析》简单讲解了关于xml模板的解析,使用到了dom4j,这篇文章其实算是个姊妹篇,都是对于目前工作中的一些任务,如xml、json相互解析所涉及到的知识。 但是相对于xml而言&am…

一篇文章读懂MySQL的各种联合查询

一篇文章读懂MySQL的各种联合查询 联合查询是指将两个或两个以上的表的数据根据一定的条件合并在一起! 联合查询主要有以下几种方式: 全连接:将一张表的数据与另外一张表的数据彼此交叉联合查询出来 举例如下: 先建两张表: CR…

一篇文章看懂@Scheduled定时器/@Async/CompletableFuture

一篇文章看懂Scheduled定时器/Async/CompletableFuture Scheduled注解解析: 1.cron:最重要的一个参数 cron表达式[秒] [分] [小时] [日] [月] [周] [年]([年]可省略) 简单了解一下,网上有现成的工具 示例&#xff…

一篇搞懂HTTP协议

本文转自 :flyhero 码上实战《一个HTTP打趴80%面试者》 HTTP协议简介 HTTP(超文本传输协议)是应用层上的一种客户端/服务端模型的通信协议,它由请求和响应构成,且是无状态的。(暂不介绍HTTP2) 协议&…

Jackson高级操作————节点树

引言 继《Jackson快速入门》基础篇之后的树模型相关操作。 节点树模型 ObjectMapper构建JsonNode节点树,类似于DOM解析器的XML。 Testpublic void testJsonTree() throws JsonProcessingException, IOException {String jsonString "{\"name\":\…

Jackson高级操作————流式API与JsonGenerator、JsonParser

引言 继《Jackson快速入门》之后的高级相关操作。 Jackson提供了一种对于性能要求应用程序操作json更加高效的方式——流式API,这种方式开销小,性能高,因此,如果应用程序或者程序逻辑对于性能有一定要求,可以使用这种…

Mysql高级教程思维导图

Mysql高级教程思维导图 1、思维导图总览: 2、MySQL架构介绍: 2.1、MySQL简介 2.2、MySQL Linux版安装 2.3、MySQL配置文件 2.4、MySQL逻辑架构介绍 2.5、MySQL存储引擎 2.6、MySQL的用户和权限管理 2.7、MySQL一些杂项配置 ’ 3、索引优化分析 3.1、性…

Eclipse(STS 4)闪退导致EGit插件异常

引言 到目前为止,STS已经闪退过三次了。 问题很棘手,我需要冷静。 首先出现了一个问题就是,EGit无法commit。 第二个问题是切换分支报错。 闪退重启后EGit无法提交代码 观察闪退出现的时机,一般出现在我 commit 代码的时候&…

spring源码分析第二天------spring系统概述以及IOC实现原理

1、Spring5 概述 Spring 是一个开源的轻量级 Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架, 其目的是用于简化企业级应用程序开发。 Spring 框架除了帮我们管理对象及其依赖关系,还提供像通…

Linux进阶之路————Linux概述

引言 Linux是一个开源、免费的操作系统。学习Linux知识分为以下几个阶段: 第一阶段:Linux环境下的基本操作命令,包括文件操作命令(rm、mkdir、chmod、chown)编辑工具使用(vi、vim)Linux用户管…

spring源码分析第三天------spring核心IOC容器和依赖注入原理

基于XML的依赖注入 1、依赖注入发生的时间 当 Spring IOC 容器完成了 Bean 定义资源的定位、载入和解析注册以后,IOC 容器中已经管理类 Bean 定义的相关数据,但是此时 IOC 容器还没有对所管理的 Bean 进行依赖注入,依赖注入在以下两种情况 …

JavaWeb中监听器Listener+过滤器filter+拦截器interceptor区别

JavaWeb中监听器Listener过滤器filter拦截器interceptor区别 如果从整个项目中看,一个servlet请求的执行过程就变成了这样context-param–>listener–>filter–>servlet–>interceptor(指的是拦截器) 1.概念 context-param:就是一些需要初…

Linux进阶之路————开机、重启和用户登录注销

关机、重启命令 shutdown 命令: 1)shutdown -h now 立即关机 2)shutdown -h 1 1分钟之后关机 3)shutdown -r now 立即重启 reboot 命令,直接使用,表示立即重启 halt 命令&am…

spring源码分析第四天------springmvc核心原理及源码分析

spring源码分析第四天------springmvc核心原理及源码分析 1、基础知识普及 2、 SpringMVC请求流程 3、SpringMVC代码流程 4、springMVC源码分析 4.1 4.2 4.3 5、Spring MVC 的优化 补充: SpringMVC经典设计是handlerMapping,大家可以看一…

Linux进阶之路————用户管理

引言 前面几篇关于Linux的已经大概领略了Linux的风采,本篇用户管理,将着重总结日常工作中,非常重要的用户管理功能。 主要包括:新增用户、删除用户、查询用户信息、指定/修改密码、切换用户、用户组,以及与用户管理相…

spring源码分析第五天------springAOP核心原理及源码分析

spring源码分析第五天------springAOP核心原理及源码分析 1、 面向切面编程。可以通过预 编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术 切面(Aspect) 连接点(Joinpoint) 通知&#x…

Linux进阶之路————Linux运行级别(重置密码)

引言 前面的《Linux进阶之路————开机、重启和用户登录注销》已经简单介绍过Linux系统运行级别的概念,今天来详细介绍和总结一下Linux的运行级别。 inittab配置文件 在配置文件目录下有一个inittab文件/etc/inittab,用于专门存储系统的运行级别&am…