介绍
- 模版方法模式 (Template Method Pattern) , 又叫模版模式(Template Pattern),在一个抽象类公开定义类执行它的方法的模版。它的子类可以按需要重写方法实现,但调用将以抽象类中定义但方式进行。
- 模版方法模式定义类一个操作中但算法但骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法但结构,就可以重定义该算法但某些特征
- 模版方法模式属于行为型模式
原理图解析:
- AbstractClass:抽象类,类中实现类模版方法(template),定义了算法但骨架,具体子类需要去实现其他的抽象方法
- ConcreteClass :子类,完成算法中特定子类的步骤
案列:
豆浆制作问题
- 制作豆浆的流程 选材 —> 添加配料 —> 浸泡 —> 放到豆浆机打碎
- 通过替阿甲不同的配料,可以制作出不同口味的豆浆
- 选材、浸泡的放到豆浆机这几个步骤 对于美中口味的豆浆都是一样的
编写模版类
public abstract class SoyaMilk {
/**
* 模版方法 final不让子类覆盖
*/
final void make(){
select();
addCondiments();
soak();
beat();
}
/**
* 选材料
*/
private void select(){
System.out.println("第一步:选择好的新鲜的豆浆");
}
/**
* 添加不同的材料
*/
abstract void addCondiments();
/**
* 浸泡
*/
private void soak(){
System.out.println("第三部,开始浸泡");
}
/**
* 放到豆浆机
*/
private void beat(){
System.out.println("第四步:放到豆浆机");
}
}
子类实现
public class BlackBeanSoyaMilk extends SoyaMilk{
@Override
void addCondiments() {
System.out.println("黑豆");
}
}
public class PeanutSoyaMilk extends SoyaMilk{
@Override
void addCondiments() {
System.out.println("花生");
}
}
客户端
public class Client {
public static void main(String[] args) {
System.out.println("---制作黑豆豆浆---");
SoyaMilk soyaMilk = new BlackBeanSoyaMilk();
soyaMilk.make();
System.out.println("---制作花生豆浆---");
SoyaMilk soyaMilk1 = new PeanutSoyaMilk();
soyaMilk1.make();
}
}
模版方法模式的钩子方法
- 在模版方法模式的父类中,我妈可以定义一个方法,它默认不做任何事,子类可以看情况可不可以覆盖他,该方法称为钩子
public abstract class SoyaMilk {
/**
* 模版方法 final不让子类覆盖
*/
final void make(){
select();
if(customerWantCondiments()){
addCondiments();
}
soak();
beat();
}
/**
* 选材料
*/
private void select(){
System.out.println("第一步:选择好的新鲜的豆浆");
}
/**
* 添加不同的材料
*/
abstract void addCondiments();
/**
* 浸泡
*/
private void soak(){
System.out.println("第三部,开始浸泡");
}
/**
* 放到豆浆机
*/
private void beat(){
System.out.println("第四步:放到豆浆机");
}
/**
* 钩子方法
*/
boolean customerWantCondiments(){
return true;
}
}
实现钩子
public class PureSoyaMilk extends SoyaMilk{
@Override
void addCondiments() {
System.out.println("不加东西");
}
@Override
boolean customerWantCondiments() {
return false;
}
}
客户端
public class Client {
public static void main(String[] args) {
System.out.println("---制作豆浆---");
SoyaMilk soyaMilk2 = new PureSoyaMilk();
soyaMilk2.make();
}
}
Spring中的模板方法模式
Spring中几乎所有的扩展,都使用了模板方法模式,这里说下IoC部分的模板方法模式!
- 定义一个接口ConfigurableApplicationContext,声明模板方法refresh
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.context;
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
/**
* 模版方法
*/
void refresh() throws BeansException, IllegalStateException;
}
- 抽象类 抽象类AbstractApplicationContext实现了接口 。实现类refresh 方法 是各种IOC容器初始化的入口)的逻辑
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
//为刷新做好准备
this.prepareRefresh();
//方法如下,调用了了两个抽象方法refreshBeanFactory、getBeanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//准备bean工厂
this.prepareBeanFactory(beanFactory);
try {
// 钩子方法
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
//钩子方法
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
return this.getBeanFactory();
}
- 这里最主要有一个抽象方法obtainFreshBeanFactory、两个钩子方法postProcessBeanFactory和onRefresh,看看他们在类中的定义
两个钩子方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
protected void onRefresh() throws BeansException {
}
我们查看 AbstractApplicationContext 实现类
AbstractRefreshableApplicationContext 子类 重写了 getBeanFactory()方法
public final ConfigurableListableBeanFactory getBeanFactory() {
DefaultListableBeanFactory beanFactory = this.beanFactory;
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory not initialized or already closed - call 'refresh' before accessing beans via the ApplicationContext");
} else {
return beanFactory;
}
}
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
GenericApplicationContext 子类 重写了 getBeanFactory()方法
private final DefaultListableBeanFactory beanFactory;
@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}
github Demo地址 : ~~~传送门~~~
个人博客地址:http://blog.yanxiaolong.cn/