模板方法设计模式
1. 简单介绍
模板方法设计模式是一种结构型设计模式。该模式定义了一个算法的骨架(方法执行的步骤),将算法的各个步骤的具体实现,交由子类完成。模板方法设计模式,让开发者只需要关注算法实现各个细节,而不必关系算法实现的全部流程。
2. 使用场景
- 具有统一的算法骨架,即方法执行步骤是固定不变的
- 针对不同的场景,存在多个具有相同操作步骤的应用场景,但部分算法的实现细节有所差异
3. 场景举例
Spring中的事务管理的设计采用了模板方法设计模式。事务的使用步骤可以抽象为:开启事务、相关操作、提交事务。针对上述步骤中的“开启事务”和“提交事务”,可由模板方法进行固定。而具体的“相关操作”,针对不同的子类可以有不同的实现。
4. UML类图
5. 具体实现
描述
- 背景:活字印刷术,可以根据自己的需求,组合不同的汉字,将组合后的汉字按顺序印刷出自己想要的词组或句子,现假设现有一块印刷版支持三个字的组合,任意组合
AbstractPrintBoard
:AbstractClass
角色,表示印刷版,用于用户自由组合三个汉字进行印刷PrintBoardOne
:ConcreteClass
角色,可对“你”、“真”、“好”三个汉字进行组合印刷PrintBoardTwo
:ConcreteClass
角色,可对“你”、“真”、“坏”三个汉字进行组合印刷
实现代码
AbstractPrintBoard.java
/**
* 角色:AbstractClass
* 印刷版,用于用户自由组合三个汉字进行印刷
*/
public abstract class AbstractPrintBoard {
/**
* 模版方法:控制汉字印刷顺序
* 先印刷 chineseCharacter1、再印刷 chineseCharacter2,最后印刷 chineseCharacter3
*/
public void print() {
System.out.println(String.format("%c%c%c", chineseCharacter1(), chineseCharacter2(), chineseCharacter3()));
}
/**
* 交由具体子类进行实现(具体哪几个汉字进行组合)
*/
public abstract char chineseCharacter1();
public abstract char chineseCharacter2();
public abstract char chineseCharacter3();
}
PrintBoardOne.java
/**
* 角色:具体实现子类
* 组合“你”、“真”、“好”三个汉字进行印刷
*/
public class PrintBoardOne extends AbstractPrintBoard {
@Override
public char chineseCharacter1() {
return '你';
}
@Override
public char chineseCharacter2() {
return '真';
}
@Override
public char chineseCharacter3() {
return '好';
}
}
PrintBoardTwo.java
/**
* 角色:具体实现子类
* 组合“你”、“真”、“坏”三个汉字进行印刷
*/
public class PrintBoardTwo extends AbstractPrintBoard {
@Override
public char chineseCharacter1() {
return '你';
}
@Override
public char chineseCharacter2() {
return '真';
}
@Override
public char chineseCharacter3() {
return '坏';
}
}
Client.java
/**
* 模版方法模式具体使用
*/
public class Client {
public static void main(String[] args) {
// AbstractPrintBoard控制了印刷汉字的顺序,具体印刷哪几个汉字,加油子类进行实现
// 印刷“你真好”三个汉字,输出:你真好
AbstractPrintBoard board1 = new PrintBoardOne();
board1.print();
// 印刷“你真坏”三个汉字,输出:你真坏
AbstractPrintBoard board2 = new PrintBoardTwo();
board2.print();
}
}
7. 源码展示
Spring源码中的ApplicationContex
的部分功能的实现实现采用了模板方法设计模式。其中模板方法模式中抽象类角色对应AbstractApplicationContext
,该类中定义了refresh()
方法的流程步骤,即模板方法。具体子类角色对应的类为GenericApplicationContext
,并实现了抽象方法refreshBeanFactory()
。
AbstractApplicationContext.java
/**
* 角色:模板方法中的抽象类
*/
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
/**
* refresh()相当于模版方法模式中的模板方法,确保了刷新的具体步骤
* 部分具体的刷新步骤交给其子类进行具体的实现
*/
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// obtainFreshBeanFactory()方法调用了抽象方法refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// 抽象方法,交由子类实现
postProcessBeanFactory(beanFactory);
} catch (BeansException ex) {
......
} finally {
......
}
}
}
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;
/**
* 默认是空实现的抽象方法,也称为钩子方法
* 子类可按需求,选择是否进行重写
*/
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
}
GenericApplicationContext.java
/**
* 角色:模板方法中的具体子类
*/
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
/**
* 抽象方法的具体实现
*/
@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());
}
}