模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
2) 简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定 步骤
3) 这种类型的设计模式属于行为型模式
编写制作豆浆的程序,说明如下:
1.定义抽象类,提供抽象方法
SoyaMilk是抽象类,make是制作豆浆的抽象方法,只需要根据放入原料的不同就可以制造不同口味的豆浆,所以添加原料是一个抽象方法,交给子类去实现,调用的时候通过不同的子类对象就可以制作不同口味的豆浆
public abstract class SoyaMilk {
final void make(){
select();
addCondiments();
soak();
bead();
}
void select(){
System.out.println("1.选择新鲜黄豆");
}
abstract void addCondiments();
void soak(){
System.out.println("3.开始浸泡");
}
void bead(){
System.out.println("4.黄豆和配料放在豆浆机打碎");
}
}
2.提供子类重写抽象方法
制作花生豆浆子类:
public class PeanutSoyaMilk extends SoyaMilk {
@Override
void addCondiments() {
System.out.println("2.添加花生原料");
}
}
制作红豆豆浆子类:
public class RedBeanSoyaMilk extends SoyaMilk{
@Override
void addCondiments() {
System.out.println("2.添加红豆配料");
}
}
3.方法测试
public class TemplateTest {
public static void main(String[] args) {
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
peanutSoyaMilk.make();
redBeanSoyaMilk.make();
}
}
运行结果:
1.在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
2.还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造
抽象方法改造,提供空实现
void addCondiments(){};
制作原味豆浆实现类
public class OriginalMilk extends SoyaMilk{
@Override
void addCondiments() {
super.addCondiments();
}
}
子类视情况而定是否要覆盖父类方法。
在Spring源码中,就使用到了模板方法模式,就在容器刷新的方法中
ConfigurableApplicationContext接口中定义了一个抽象方法refresh
在其实现类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();
}
}
}
这个方法是Spring最重要的容器刷新的方法,我们看看在refresh方法中Spring通过模板方法模式留下了多少扩展点
1.obtainFreshBeanFactory()方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
在obtainFreshBeanFactory的方法中refreshBeanFactory()和getBeanFactory()都是抽象方法,只能子类去实现,主要是为了初始化Spring容器并获取子类创建的BeanFactoy
2.postProcessBeanFactory(beanFactory)方法
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
它是一个钩子方法,交给子类去实现
3.onRefresh()方法
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}
它是一个钩子方法,交给子类去实现
基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改。
2) 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接 使用。
3) 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
4) 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加, 使得系统更加庞大
5) 一般模板方法都加上final关键字, 防止子类重写模板方法.
6) 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一 系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理