模板设计模式在 Java 里是一种行为设计模式,它在抽象类里定义算法的骨架,把部分步骤的具体实现延迟到子类。如此一来,子类可以在不改变算法结构的基础上,重新定义算法中的特定步骤。
模式组成
抽象类(Abstract Class):定义了算法的骨架,其中包含模板方法与抽象方法。模板方法是具体方法,它规定了算法的步骤,并且会调用抽象方法;抽象方法则由子类去实现。
具体子类(Concrete Subclass):实现抽象类中的抽象方法,完成算法中特定步骤的具体操作。 代码示例
下面是一个用 Java 实现模板设计模式的示例,以制作饮料为例:
// 抽象类
abstract class Beverage {
// 模板方法,定义制作饮料的算法骨架
public final void prepareBeverage() {
boilWater();
brew();
pourInCup();
addCondiments();
}
public void boilWater() {
System.out.println("Boiling water");
}
public void pourInCup() {
System.out.println("Pouring into cup");
}
// 抽象方法,由子类实现
public abstract void brew();
public abstract void addCondiments();
}
// 具体子类:咖啡
class Coffee extends Beverage {
@Override
public void brew() {
System.out.println("Dripping coffee through filter");
}
@Override
public void addCondiments() {
System.out.println("Adding sugar and milk");
}
}
// 具体子类:茶
class Tea extends Beverage {
@Override
public void brew() {
System.out.println("Steeping the tea");
}
@Override
public void addCondiments() {
System.out.println("Adding lemon");
}
}
// 测试类
public class TemplatePatternDemo {
public static void main(String[] args) {
Beverage coffee = new Coffee();
System.out.println("Making coffee:");
coffee.prepareBeverage();
System.out.println("\nMaking tea:");
Beverage tea = new Tea();
tea.prepareBeverage();
}
}
代码解释
Beverage类属于抽象类,prepareBeverage方法是模板方法,它定义了制作饮料的通用步骤。brew和addCondiments是抽象方法,要由子类来实现。
Coffee和Tea类为具体子类,它们实现了brew和addCondiments方法,完成了制作咖啡和茶的特定步骤。
优点
代码复用:模板方法定义了算法的骨架,避免了在多个子类中重复编写相同的代码。
可扩展性:子类能够根据需求重写抽象方法,实现自身的业务逻辑。
缺点
类数量增加:每一个不同的实现都需要一个子类,这可能会导致类的数量增加,使系统更加复杂。 灵活性受限:由于模板方法定义了算法的骨架,子类只能在特定的步骤上进行扩展,可能会限制算法的灵活性。
public final void prepareBeverage(),final修饰里面的方法,不能重写,里面的方法却能重写,我很混乱,通俗易懂解释一下
在模板方法模式中,prepareBeverage()
被声明为 final
是为了确保算法的整体流程不被子类修改,而内部的 brew()
和 addCondiments()
被声明为 abstract
是为了强制子类实现具体的细节。这种设计实现了“固定流程,灵活扩展”的效果。
通俗解释:
为什么用
final
?
prepareBeverage()
是制作饮料的固定流程(烧水 → 冲泡 → 倒杯 → 加调料),用final
表示“这个流程不能被子类篡改”。比如,子类不能把顺序改成“先加调料再烧水”。为什么内部的
brew()
和addCondiments()
可以重写?
这两个方法是抽象方法(abstract
),子类必须实现它们。父类只定义流程(“要冲泡”和“要加调料”),但具体怎么冲泡、加什么调料,由子类自己决定。例如:咖啡冲泡是“用滤纸滴漏”,加“糖和牛奶”。
茶冲泡是“用热水浸泡茶叶”,加“柠檬”。
类比现实场景:
想象一个“烹饪机器人”的模板:
固定流程(
final
方法):
它的做菜步骤是固定的:开火 → 放食材 → 翻炒 → 关火。灵活扩展(抽象方法):
但具体“放什么食材”、“怎么翻炒”由用户决定(比如做西红柿炒蛋还是青椒肉丝)。
代码验证:
如果子类尝试重写 prepareBeverage()
,会直接编译报错:
class Coffee extends Beverage {
// ❌ 编译错误!不能重写 final 方法
@Override
public void prepareBeverage() {
// 非法操作!
}
}
但子类必须实现抽象方法:
class Coffee extends Beverage {
@Override
public void brew() { /* 必须实现 */ } // ✅
@Override
public void addCondiments() { /* 必须实现 */ } // ✅
}
总结:
final
方法:保护算法流程的完整性(“怎么做”)。abstract
方法:定义子类必须实现的扩展点(“做什么”)。
这就是模板方法模式的核心:在父类控制流程,在子类实现细节。