模板模式
1.需求:如何制作豆浆?
- 制作豆浆的流程: 选材 -> 添加配料 -> 浸泡 -> 放到豆浆机里打碎
- 制作豆浆的逻辑大体相同,在添加配料的时候可以选择添加不同的配料制作不同的豆浆(红豆豆浆,花生豆浆)
- 解决方法: 使用模板模式模拟制作豆浆的过程
2.模板模式介绍
-
模板模式(Template Pattern)又称为模板方法模式(Template Method Pattern),在一个抽象类中公开定义了执行逻辑,它的子类可以去重写该方法,定制该逻辑
-
模板模式就像是一个骨架,定义一个抽象的执行结构
-
模板模式中的角色:
- .AbstractClass: 抽象类,内部有一个模板方法(template),规定了算法大致的流程(算法骨架)
- ConcreteClass: 子类,内部重新实现抽象方法。不一样的子类可以实现不一样的方法
-
什么是钩子方法:
- 在模板模式的抽象类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况是否需要覆盖该方法
- 假设我们现在需要追加需求:**如何制作纯豆浆?**如何修改代码? => 在设计添加逻辑时,设置一个钩子函数判断该方法是否执行。
-
模板模式的结构图:
3.代码演示
- uml
- 代码一览
package com.liz.GOF23.template_method;
//抽象类,表示豆浆
public abstract class SoyaMilk {
//模板方法,不让子类覆盖
final void make() {
//流程一览
select();
//此处是为了制作纯豆浆,设计的逻辑
if(isAdd()){
add();
}
soak();
beat();
}
//选材
void select() {
System.out.println("第一步:选择材料");
}
//添加配料(配料可能不同)
public abstract void add();
//浸泡
void soak() {
System.out.println("第三步:浸泡");
}
//打磨
void beat() {
System.out.println("第四步:打磨");
}
//钩子方法,判断是否需要添加配料(如何在子类中重写为false 则默认不执行add方法 [见make逻辑])
boolean isAdd(){
return true;
}
}
//实现类1
package com.liz.GOF23.template_method;
//红豆豆浆
public class RedBeanSoyaMilk extends SoyaMilk {
@Override
public void add() {
System.out.println("第三步:加入红豆");
}
}
//实现类2
public class PeanutSoyaMilk extends SoyaMilk {
@Override
public void add() {
System.out.println("第三步:加入花生");
}
}
//实现类2
public class PureSoyaMilk extends SoyaMilk {
@Override
public void add() {
//空实现
}
//此时不会去调用add方法
@Override
boolean isAdd() {
return false;
}
}
//调用者
public static void main(String[] args) {
SoyaMilk red = new RedBeanSoyaMilk();
SoyaMilk peanut = new PeanutSoyaMilk();
//调用模板方法
red.make();
System.out.println("-----------------------");
peanut.make();
System.out.println("-----------------------");
//实现钩子方法 调用纯豆浆
SoyaMilk pure = new PureSoyaMilk();
pure.make();
}
}
- 执行结果:
4.模板模式细节
-
一般在模板方法上加上final关键字,防止子类重写模板方法(见上述抽象类中的make方法)
-
模板方法的优缺点
- 优点:
- 封装不变的部分,修改可变的部分
- 提取公共的代码,便于维护
- 行为由父类控制,子类控制(符合开闭原则)
- 代码复用性高,降低代码的冗余度
- 缺点:
- 每一种不同的实现都要加上一个子类
- 由于继承的关系,父类增加或者修改方法的时候,子类都需要实现
- 优点:
-
模板模式的适用环境:当完成某个过程时,该过程需要执行一系列步骤(一系列步骤基本相同),但是个别步骤在实现的时候可能细节不同的时候,可以使用模板模式(+钩子函数)来处理。
参考资料:
韩顺平:java设计模式
https://www.jianshu.com/p/c3a5b653b0d3