第十四章:模板方法
一、基本介绍
现在我现在需要写一个程序来让机器人做奶茶,做奶茶的过程可以分为加奶粉、冲泡、加配料、包装几个过程。无论是做一杯什么口味的奶茶,它的步骤都是这几步,所以我就可以定义一个抽象类,做奶茶的各个步骤声明成抽象方法,不过大致的制作流程在这个抽象类中做实现
类图如下:
二、具体实现
MilkyTea 抽象类
public abstract class MilkyTea {
// 方法的调用逻辑由父类决定
void make() {
addPowder();
addWater();
addCompound();
encapsulation();
}
// 具体实现可能需要子类完成或覆盖
abstract void addPowder();
void addWater() {
System.out.println("加入适量白开水");
}
abstract void addCompound();
void encapsulation() {
System.out.println("封装奶茶");
}
}
VanillaMilkTea 子类
public class VanillaMilkTea extends MilkyTea {
@Override
void addPowder() {
System.out.println("添加香草味奶粉");
}
@Override
void addCompound() {
System.out.println("添加椰果");
}
}
RedBeanMilkTea 子类
public class RedBeanMilkTea extends MilkyTea {
@Override
void addPowder() {
System.out.println("添加原为奶粉");
}
@Override
void addCompound() {
System.out.println("添加大量红豆");
}
}
测试类
public class TemplateTest {
public static void main(String[] args) {
VanillaMilkTea vanillaMilkTea = new VanillaMilkTea();
System.out.println("制作香草奶茶");
vanillaMilkTea.make();
System.out.println("============");
System.out.println("制作红豆奶茶");
RedBeanMilkTea redBeanMilkTea = new RedBeanMilkTea();
vanillaMilkTea.make();
}
}
钩子方法:我们在抽象父类中规定了方法的调用逻辑,但有时候某些方法并不一定需要执行,需要子类来决定。但是我们不太愿意让子类重写已经在父类中规定的调用逻辑,那怎么办?这时可以用一个钩子方法的返回值来决定方法的执行与否,子类通过重写钩子方法间接影响了调用的逻辑
改造后的 MilkyTea 父类
public abstract class MilkyTea {
void make() {
addPowder();
addWater();
// 让子类也有一定决定权
if (isCompoundNeed())
addCompound();
encapsulation();
}
abstract void addPowder();
void addWater() {
System.out.println("加入适量白开水");
}
abstract void addCompound();
void encapsulation() {
System.out.println("封装奶茶");
}
boolean isCompoundNeed() {
return true;
}
}
VanillaMilkTea 不加香草
public class VanillaMilkTea extends MilkyTea {
@Override
void addPowder() {
System.out.println("添加香草味奶粉");
}
@Override
void addCompound() {
System.out.println("添加椰果");
}
// 重写钩子方法,不加椰果
@Override
boolean isCompoundNeed() {
return false;
}
}
三、模板总结
1)算法(方法的调用逻辑)父类中做了实现,子类的作用就是对具体步骤做实现
2)一般模板方法都会加上 final 来防止子类的重写
3)一旦大的调用逻辑需要改变,只用改变父类一个类
4)子类可以通过不同的实现完成不同的功能