模板设计模式在 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 {@Overridepublic void brew() {System.out.println("Dripping coffee through filter");}@Overridepublic void addCondiments() {System.out.println("Adding sugar and milk");}
}// 具体子类:茶
class Tea extends Beverage {@Overridepublic void brew() {System.out.println("Steeping the tea");}@Overridepublic 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 方法@Overridepublic void prepareBeverage() { // 非法操作!}
}
但子类必须实现抽象方法:
class Coffee extends Beverage {@Overridepublic void brew() { /* 必须实现 */ } // ✅@Overridepublic void addCondiments() { /* 必须实现 */ } // ✅
}
总结:
-
final
方法:保护算法流程的完整性(“怎么做”)。 -
abstract
方法:定义子类必须实现的扩展点(“做什么”)。
这就是模板方法模式的核心:在父类控制流程,在子类实现细节。