文章目录
- 一、类型
- 二、定义
- 三、参与者
- 四、UML类图
- 五、示例
- 六、总结
- 参考文章
一、类型
行为类模式
二、定义
定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤。
三、参与者
1、AbstractClass抽象类:实现一个模板方法,定义算法的骨架,具体的子类将实现这些方法以实现算法的各个步骤;
2、ConcreteClass:具体的子类,实现抽象方法,以完成算法中的各个步骤。
四、UML类图
说明:
- AbstractClass 是抽象类,它有一个模板方法
template()
,定义了算法骨架,一般使用final
进行修饰,防止子类重写模板方法;而operation
就是具体的算法步骤,由子类来实现; - ConcreteClass 是实现类,它主要用于实现抽象类中具体的算法步骤。
五、示例
钩子方法:在模板方法模式的父类中,可以定义一个默认不做任何事的方法,子类视情况选择是否覆盖它。该方法就被成为钩子。
我们使用一个制作豆浆的例子来说明。
制作豆浆的步骤如下:选材->加豆子->加糖->浸泡并放入豆浆机打碎
- 加豆子这个步骤,我们可以加黄豆或加红豆,我们将其做做成抽象方法,让子类去实现;
- 加糖这个步骤,我们可以选择或不加,我们可以使用一个钩子方法来进行控制。
1、AbstractSoyaMilk:定义豆浆抽象类,定义了一个make
模板方法,其定义了算法骨架即豆浆的制作流程;同时定义了一个钩子方法isAddSugar
,子类可以进行覆盖,以决定是否加糖。
// 抽象类,表示豆浆的制作流程
public abstract class AbstractSoyaMilk {
// 模板方法make,使用final修饰,防止子类覆盖
final void make() {
select();
addBean();
if (isAddSugar()) {
addSugar();
}
beat();
}
// 第一步:选材
void select() {
System.out.println("选材");
}
// 第二步:添加豆子
abstract void addBean();
// 第三步:加糖
void addSugar() {
System.out.println("加糖");
}
// 第四步:浸泡并放入豆浆机
void beat() {
System.out.println("浸泡并放入豆浆机");
}
// 钩子方法,决定是否加糖
boolean isAddSugar() {
return true;
}
}
2、RedBeanSoyaMild:AbstractSoyaMilk
抽象类的具体实现,定义方法addBean
的具体实现
// 红豆豆浆
public class RedBeanSoyaMild extends AbstractSoyaMilk {
@Override
void addBean() {
System.out.println("加入红豆");
}
}
3、PeanutSoyaMild:AbstractSoyaMilk
抽象类的具体实现,定义addBean
的具体实现;同时重写钩子方法isAddSugar
// 花生豆浆
public class PeanutSoyaMild extends AbstractSoyaMilk {
@Override
void addBean() {
System.out.println("加入花生");
}
// 覆盖钩子方法,让其返回false,不加糖
@Override
boolean isAddSugar() {
return false;
}
}
4、Client:客户端
public class Client {
public static void main(String[] args) {
System.out.println(" 制作红豆豆浆 ");
RedBeanSoyaMild redBeanSoyaMild = new RedBeanSoyaMild();
redBeanSoyaMild.make();
System.out.println(" 制作花生豆浆 ");
PeanutSoyaMild peanutSoyaMild = new PeanutSoyaMild();
peanutSoyaMild.make();
}
}
执行结果:
制作红豆豆浆
选材
加入红豆
加糖
浸泡并放入豆浆机
制作花生豆浆
选材
加入花生
浸泡并放入豆浆机
六、总结
1、基本思想
算法只存在于一个地方(即父类),容易修改。当需要修改算法时,只需要修改父类中的模板方法或已实现的某些步骤,子类就可直接继承这些修改。
2、优点和缺点
优点
- 代码复用程度高、便于维护:父类的模板方法和某些步骤可以被子类所继承,因此也便于维护。
- 统一了算法、易拓展:父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的具体实现。
缺点
- 子类多:每一个不同的实现类都需要一个子类来实现,导致类的数量增多。
3、注意
一般会在模板方法上添加 final
关键字,防止子类重写模板方法。
4、使用场景
当要完成需执行一系列步骤的过程,这些步骤基本相同,但其个别步骤在实现时可能不同时,通常考虑模板方法模式来处理。