模板方法模式 (Template Method)
在现实生活中,我们经常需要做一些重复的工作,比如做饭、洗衣、整理房间等。虽然每次的任务可能不完全相同,但这些任务通常会遵循一些相似的步骤。就像做饭时,我们会先准备食材、然后烹饪、最后清理厨房。而在每个步骤的具体操作上,可能会因为菜品的不同而有所区别。
模板方法模式(Template Method)正是通过定义一个算法的“骨架”,将一些步骤的具体实现留给子类来完成。这样,父类负责控制算法的执行流程,而子类负责实现每个步骤的细节,从而达到了代码复用和灵活扩展的目的。
趣味解读:做饭的固定流程
想象你是一个大厨,每次做菜时,虽然菜的种类不同,但做菜的基本流程却是相似的。例如:
准备食材:无论做什么菜,首先要准备好食材。
烹饪:然后根据不同的菜式,使用不同的方式进行烹饪。
清理厨房:做完饭后,清理厨房是不可缺少的步骤。
虽然每道菜在“烹饪”这一步会有不同的具体做法,但其余的步骤是一样的。你作为大厨,可以通过模板方法模式来确保每道菜都遵循这个固定流程,而具体的烹饪方式由每个菜品的厨师(子类)来定义。
Java代码案例:制作饮料
假设你要开发一个饮料制作系统,其中包括不同的饮料类型,如茶和咖啡。制作这些饮料时,它们有相似的制作流程:首先烧水、然后泡茶/煮咖啡,最后倒入杯中并提供服务。每种饮料的具体泡制方式有所不同,但其余的步骤保持不变。
// 1. 饮料制作的模板类
abstract class Beverage {
// 模板方法:定义饮料制作的固定步骤
public final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
}
// 具体步骤:烧水
private void boilWater() {
System.out.println("烧开水...");
}
// 具体步骤:将饮料泡制或煮沸
protected abstract void brew();
// 具体步骤:倒入杯中
private void pourInCup() {
System.out.println("倒入杯中...");
}
// 钩子方法:询问顾客是否需要调味品,默认返回true
protected boolean customerWantsCondiments() {
return true;
}
// 具体步骤:添加调味品
protected abstract void addCondiments();
}
// 2. 具体子类 - 茶
class Tea extends Beverage {
@Override
protected void brew() {
System.out.println("用热水泡茶...");
}
@Override
protected void addCondiments() {
System.out.println("加柠檬...");
}
}
// 3. 具体子类 - 咖啡
class Coffee extends Beverage {
@Override
protected void brew() {
System.out.println("用热水煮咖啡...");
}
@Override
protected void addCondiments() {
System.out.println("加牛奶和糖...");
}
// 重写钩子方法,决定是否添加调味品
@Override
protected boolean customerWantsCondiments() {
return false; // 咖啡不加调味品
}
}
// 4. 客户端代码
public class Main {
public static void main(String[] args) {
// 制作茶
Beverage tea = new Tea();
tea.prepareRecipe();
System.out.println();
// 制作咖啡
Beverage coffee = new Coffee();
coffee.prepareRecipe();
}
}
代码解析:
模板方法 (
prepareRecipe
):这是一个在Beverage
类中定义的模板方法,它规定了制作饮料的步骤流程。首先是烧水、泡制饮料、倒入杯中,然后根据需要添加调味品。钩子方法 (
customerWantsCondiments
):这是一个可被子类覆盖的方法,用来决定是否在饮料中加入调味品。默认情况下它返回true
,但在Coffee
类中,顾客选择不加调味品,所以该方法被重写返回false
。抽象方法 (
brew
和addCondiments
):brew
和addCondiments
方法是抽象的,必须由子类实现。这些方法在每种饮料的制作过程中有所不同,因此由子类提供具体实现。具体子类 (
Tea
和Coffee
):Tea
类和Coffee
类分别实现了brew
和addCondiments
方法,定义了茶和咖啡的具体制作步骤。Coffee
类还重写了钩子方法,决定不加调味品。
运行结果:
烧开水...
用热水泡茶...
倒入杯中...
加柠檬...
烧开水...
用热水煮咖啡...
倒入杯中...
实际应用场景
工作流系统:许多工作流或审批流程都有固定的步骤,比如审批、签名、归档等。模板方法模式可以帮助我们定义固定的流程框架,而在每个环节上执行不同的处理逻辑。
数据导入导出:导入导出的过程一般包括读取数据、验证数据、存储数据等固定步骤,而具体的读取和存储方式可以由子类根据不同的数据类型来实现。
游戏中的关卡流程:游戏中的每一关都可能遵循一个固定的流程,例如加载资源、创建关卡、开始战斗等,而每一关的具体实现则可能不同,模板方法可以用来规范这些流程。
总结
模板方法模式通过定义一个算法的“骨架”,将一些步骤的具体实现留给子类来完成。它的主要优点是代码复用和流程控制,使得系统更加灵活且易于维护。通过将固定步骤和变化的部分分开,模板方法模式使得代码结构更加清晰,便于管理复杂的流程。