模板方法
- 概述
- UML类图
- 代码栗子
- Spring源码体现
- 总结
概述
-
概述
模板方法是一种行为设计模式,它在超类(抽象类)中定义算法的框架,但允许子类覆盖算法的特定步骤而无需更改其结构。 -
作用
-
- 允许子类实现变化的行为(通过重写钩子方法)
- 避免了重复代码:算法的一般工作流程在抽象类的模板方法中实现一次,而子类中实现必要的变体。
- 控制允许专业化的点。如果子类只是简单地覆盖模板方法,则它们可以对工作流进行根本性和任意的更改。相反,通过仅覆盖钩子方法,仅可以更改工作流的某些特定细节,并且整个工作流保持不变。
UML类图
代码栗子
//动作类
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("苹果");
}
}
- 运行效果
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加载资源配置文件用的,规定了整个加载流程,但是放开了流程细节交由其子类实现
总结
- 多个子类有公有的方法,并且逻辑基本相同时。把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。
- 重构时,把相同的代码抽取到父类中,然后通过钩子函数约束其行为。