导航:
【黑马Java笔记+踩坑汇总】JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud+黑马旅游+谷粒商城+学成在线+设计模式+牛客面试题
目录
模板模式
1、基本介绍
2、模板模式解决豆浆制作问题
3、钩子方法
4、Spring 框架AbstractApplicationContext抽象类
模板模式
1、基本介绍
- 1)模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
- 2)简单说,模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
- 3)这种类型的设计模式属于行为型模式(用于描述对象之间的通信和责任分配)。
实现方式:抽象类有一个模板方法和其他行为方法,模板方法按流程调用各行为方法(抽象或非抽象);具体子类重写抽象的行为方法。
对原理类图的说明——即模板方法模式的角色和职责
AbstractClass
抽象类中实现了模板方法,定义了算法的骨架,具体子类需要去实现其抽象方法或重写其中方法
ConcreteClass
实现了抽象方法,已完成算法中特定子类的步骤
注意事项和细节
- 1)基本思想:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
- 2)实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用
- 3)既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现
- 4)不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
- 5)一般模板方法都加上final关键字,防止子类重写模板方法
- 6)使用场景:当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理
2、模板模式解决豆浆制作问题
编写制作豆浆的程序,说明如下:
- 1)制作豆浆的流程选材 ----> 添加配料 ----> 浸泡 ----> 放到豆浆机打碎
- 2)通过添加不同的配料,可以制作出不同口味的豆浆
- 3)选材、浸泡和放到豆浆机打碎这几个步骤是一个模板方法,对于制作每种口味的豆浆都是一样的
- 4)请使用模板方法模式完成
说明:因为模板方法模式比较简单,很容易就想到这个方案,因此就直接使用,不再使用传统的方案来引出模板方法模式
核心代码
/**
* 抽象方法
*/
public abstract class SoyaMilk {
/**
* 模板方法,定义为final禁止覆写
*/
public final void make() {
System.out.println(">>>>>>豆浆制作开始<<<<<<");
useSoyBean();
addIngredients();
soak();
mash();
System.out.println(">>>>>>豆浆制作结束<<<<<<");
}
// 同包可见、对其他包下的子类可见。
protected void useSoyBean() {
System.out.println("Step1. 选用上好的黄豆.");
}
//添加原材料是抽象方法,因为不同豆浆原材料不一样
protected abstract void addIngredients();
protected void soak() {
System.out.println("Step3. 对黄豆和配料进行水洗浸泡.");
}
protected void mash() {
System.out.println("Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.");
}
}
/**
* 花生豆浆
*/
public class PeanutSoyaMilk extends SoyaMilk {
public PeanutSoyaMilk() {
System.out.println("============花生豆浆============");
}
@Override
protected void addIngredients() {
System.out.println("Step2. 加入上好的花生.");
}
}
/**
* 红豆豆浆
*/
public class RedBeanSoyaMilk extends SoyaMilk {
public RedBeanSoyaMilk() {
System.out.println("============红豆豆浆============");
}
@Override
protected void addIngredients() {
System.out.println("Step2. 加入上好的红豆.");
}
}
/**
* 芝麻豆浆
*/
public class SesameSoyaMilk extends SoyaMilk {
public SesameSoyaMilk() {
System.out.println("============芝麻豆浆============");
}
@Override
protected void addIngredients() {
System.out.println("Step2. 加入上好的芝麻.");
}
}
客户端调用模板方法
SoyaMilk peanutSoyaMilk = new PeanutSoyaMilk();
peanutSoyaMilk.make();
SoyaMilk redBeanSoyaMilk = new RedBeanSoyaMilk();
redBeanSoyaMilk.make();
SoyaMilk sesameSoyaMilk = new SesameSoyaMilk();
sesameSoyaMilk.make();
/*
============花生豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的花生.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
============红豆豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的红豆.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
============芝麻豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step2. 加入上好的芝麻.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
*/
3、钩子方法
在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”
还是用上面做豆浆的例子来讲解,比如,我们还希望制作纯豆浆,不添加任何的配料,请使用钩子方法对前面的模板方法进行改造
抽象类和具体类
//抽象模板类
public abstract class SoyaMilk {
//模板方法
public final void make() {
// ...
//如果钩子方法决定加配料,就加配料;否则不执行加配料操作。
if (customAddIngredients()) {
addIngredients();
}
// ...
}
//钩子方法,决定是否需要添加配料。默认情况是加配料。
boolean customAddIngredients() {
return true;
}
// ...
}
/**
* 纯豆浆
*/
public class PureSoyaMilk extends SoyaMilk {
public PureSoyaMilk() {
System.out.println("============纯豆浆============");
}
@Override
protected void addIngredients() {
// 空实现即可
}
@Override
protected Boolean customAddIngredients() {
return false;
}
}
客户端,测试钩子方法
SoyaMilk pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.make();
/*
============纯豆浆============
>>>>>>豆浆制作开始<<<<<<
Step1. 选用上好的黄豆.
Step3. 对黄豆和配料进行水洗浸泡.
Step4. 将充分浸泡过的黄豆和配料放入豆浆机中,开始打豆浆.
>>>>>>豆浆制作结束<<<<<<
*/
4、Spring 框架AbstractApplicationContext抽象类
AbstractApplicationContext.java中有一个refresh()方法就是模板方法,它用于根据流程调用aop代理创建、bean生命周期初始化、属性注入等启动并初始化Spring应用上下文的方法。
AbstractApplicationContext抽象类是ApplicationContext接口的一种默认实现,提供了一些通用的应用上下文功能,同时也为其他具体的应用上下文实现类提供了一些可扩展的方法。
应用上下文:负责管理各种bean以及它们之间的关系,并对它们进行生命周期的管理。
// 模板方法
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;
}
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
}
protected void onRefresh() throws BeansException {
// For subclasses: do nothing by default.
}