模板模式
案例
1 2 3 4
| 编写制作豆浆的程序,说明如下: 1)制作豆浆的流程选材--->添加配料--->浸泡--->放到豆浆机打碎 2)通过添加不同的配料,可以制作出不同口味的豆浆 3)选材、浸泡和放到豆浆机打碎这几个步骤对于制作每种口味的豆浆都是一样的
|
基本介绍
- 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
- 简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
- 这种类型的设计模式属于行为型模式。
角色
AbstractClass抽象类
,类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其它的抽象方法
ConcreteClass
实现抽象方法,以完成算法中子类的步骤
解决问题
制作模板,实现共有的方法,把特定方法放到子类实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public abstract class SoyaMilk {
final void make(){ select(); addCondiments(); soak(); beat(); }
void select(){ System.out.println("第一步:选择黄豆"); }
abstract void addCondiments();
void soak(){ System.out.println("第三步:黄豆和配料一起浸泡"); }
void beat(){ System.out.println("第四步,黄豆和配料放到豆浆机去打碎"); } }
|
子类
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class RedBeanSoyaMilk extends SoyaMilk { @Override void addCondiments() { System.out.println("第二步:加入红豆"); } }
public class PeanutSoyaMilk extends SoyaMilk{ @Override void addCondiments() { System.out.println("第二步:加入花生"); } }
|
调用
1 2 3 4 5 6 7 8 9 10 11
| public class Client { public static void main(String[] args) { RedBeanSoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk(); redBeanSoyaMilk.make();
PeanutSoyaMilk peanutSoyaMilk = new PeanutSoyaMilk(); peanutSoyaMilk.make(); } }
|
模板方法模式中的钩子方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public abstract class SoyaMilk {
final void make(){ select(); if(customerWantCondiments()){ addCondiments(); } addCondiments(); soak(); beat(); }
void select(){ System.out.println("第一步:选择黄豆"); }
abstract void addCondiments();
void soak(){ System.out.println("第三步:黄豆和配料一起浸泡"); }
void beat(){ System.out.println("第四步,黄豆和配料放到豆浆机去打碎"); }
boolean customerWantCondiments(){ return true; } }
|
子类实现
1 2 3 4 5 6 7 8 9 10 11
| public class PureSoyaMilk extends SoyaMilk { @Override void addCondiments() { }
@Override boolean customerWantCondiments() { return false; } }
|
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Client { public static void main(String[] args) { RedBeanSoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk(); redBeanSoyaMilk.make();
PeanutSoyaMilk peanutSoyaMilk = new PeanutSoyaMilk(); peanutSoyaMilk.make();
PureSoyaMilk pureSoyaMilk = new PureSoyaMilk(); pureSoyaMilk.make(); } }
|
在Spring中的模板方法
在Spring IOC中使用了模板方法
ConfigurableApplicationContext
中有个方法refresh
方法
1 2 3
| public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable { void refresh() throws BeansException, IllegalStateException; }
|
查看子类,这个方法里面的方法都是钩子方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try { postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh(); }
catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); }
destroyBeans();
cancelRefresh(ex);
throw ex; }
finally { resetCommonCaches(); } } } protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; } }
|
GenericApplicationContext
子类实现了
1 2 3 4 5 6 7 8 9 10
| 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()); } }
|
注意事项
- 基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
- 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
- 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
- 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
- 一般模板方法都加上
final
关键字,防止子类重写模板方法.
- 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理