本文目录导读:

Java模板方法模式案例
模板方法模式是一种行为设计模式,它定义一个操作中的算法骨架,而将一些步骤延迟到子类中,下面通过几个实际案例来演示。
案例1:游戏制作模板
基础模板类
// 游戏模板
public abstract class Game {
// 模板方法 - 定义游戏流程
public final void play() {
// 初始化游戏
initGame();
// 开始游戏
startPlay();
// 结束游戏
endPlay();
// 可选钩子方法
if (isAddBonus()) {
addBonus();
}
}
// 抽象方法 - 子类必须实现
protected abstract void initGame();
protected abstract void startPlay();
protected abstract void endPlay();
// 钩子方法 - 子类可选覆盖
protected boolean isAddBonus() {
return false;
}
protected void addBonus() {
System.out.println("添加额外奖励");
}
}
具体子类实现
// 足球游戏
public class FootballGame extends Game {
@Override
protected void initGame() {
System.out.println("足球游戏初始化:创建22名球员,准备足球场");
}
@Override
protected void startPlay() {
System.out.println("足球游戏开始:开球,比赛进行中");
}
@Override
protected void endPlay() {
System.out.println("足球游戏结束:裁判吹响终场哨");
}
// 覆盖钩子方法
@Override
protected boolean isAddBonus() {
return true;
}
@Override
protected void addBonus() {
System.out.println("足球游戏特殊奖励:最佳球员额外获得10分");
}
}
// 篮球游戏
public class BasketballGame extends Game {
@Override
protected void initGame() {
System.out.println("篮球游戏初始化:创建10名球员,准备篮球场");
}
@Override
protected void startPlay() {
System.out.println("篮球游戏开始:跳球,比赛开始");
}
@Override
protected void endPlay() {
System.out.println("篮球游戏结束:计时器响铃");
}
}
测试代码
public class TemplateMethodDemo {
public static void main(String[] args) {
System.out.println("=== 足球游戏 ===");
Game football = new FootballGame();
football.play();
System.out.println("\n=== 篮球游戏 ===");
Game basketball = new BasketballGame();
basketball.play();
}
}
输出结果
=== 足球游戏 ===
足球游戏初始化:创建22名球员,准备足球场
足球游戏开始:开球,比赛进行中
足球游戏结束:裁判吹响终场哨
足球游戏特殊奖励:最佳球员额外获得10分
=== 篮球游戏 ===
篮球游戏初始化:创建10名球员,准备篮球场
篮球游戏开始:跳球,比赛开始
篮球游戏结束:计时器响铃
案例2:数据导出系统
导出模板类
// 数据导出模板
public abstract class DataExporter {
// 模板方法 - 定义导出流程
public final void exportData(String data) {
System.out.println("===== 开始导出数据 =====");
// 1. 验证数据
if (!validateData(data)) {
System.out.println("数据验证失败,导出终止");
return;
}
// 2. 处理数据
String processedData = processData(data);
// 3. 写入文件
writeToFile(processedData);
// 4. 发送通知
sendNotification();
System.out.println("===== 导出完成 =====");
}
// 抽象方法
protected abstract boolean validateData(String data);
protected abstract String processData(String data);
protected abstract void writeToFile(String data);
// 具体方法
protected void sendNotification() {
System.out.println("发送导出完成通知");
}
// 钩子方法
protected boolean needValidation() {
return true;
}
}
具体导出类
// CSV导出器
public class CSVExporter extends DataExporter {
@Override
protected boolean validateData(String data) {
System.out.println("CSV格式验证:检查逗号分隔格式");
return data != null && data.contains(",");
}
@Override
protected String processData(String data) {
System.out.println("CSV数据处理:添加表头和数据行");
return "ID,名称,价格\n" + data;
}
@Override
protected void writeToFile(String data) {
System.out.println("写入CSV文件:export.csv");
System.out.println("文件内容:\n" + data);
}
}
// PDF导出器
public class PDFExporter extends DataExporter {
@Override
protected boolean validateData(String data) {
System.out.println("PDF格式验证:检查数据完整性");
return data != null && !data.isEmpty();
}
@Override
protected String processData(String data) {
System.out.println("PDF数据处理:添加PDF标记和字体信息");
return "%PDF-1.4\n" + data + "\n%%EOF";
}
@Override
protected void writeToFile(String data) {
System.out.println("写入PDF文件:export.pdf");
System.out.println("文件内容:\n" + data);
}
}
测试代码
public class ExportDemo {
public static void main(String[] args) {
// CSV导出
System.out.println("=== CSV导出 ===");
DataExporter csvExporter = new CSVExporter();
csvExporter.exportData("1,苹果,5.5\n2,香蕉,3.2");
System.out.println("\n=== PDF导出 ===");
DataExporter pdfExporter = new PDFExporter();
pdfExporter.exportData("商品列表\na. 苹果 - 5.5元\nb. 香蕉 - 3.2元");
}
}
案例3:银行取款流程
银行模板类
// 银行取款模板
public abstract class BankTransaction {
// 模板方法 - 定义取款流程
public final void withdraw(String account, double amount) {
System.out.println("===== 取款流程开始 =====");
// 1. 验证账户
if (!verifyAccount(account)) {
System.out.println("账户验证失败");
return;
}
// 2. 验证余额
if (!verifyBalance(account, amount)) {
System.out.println("余额不足");
return;
}
// 3. 执行取款
double fee = calculateFee(amount);
double actualAmount = amount - fee;
executeWithdrawal(account, actualAmount);
// 4. 记录交易
logTransaction(account, actualAmount, fee);
// 5. 可选发送短信
if (needSendSMS()) {
sendSMS("取款成功:" + actualAmount + "元,手续费:" + fee + "元");
}
System.out.println("===== 取款流程结束 =====");
}
// 抽象方法
protected abstract boolean verifyAccount(String account);
protected abstract boolean verifyBalance(String account, double amount);
protected abstract void executeWithdrawal(String account, double amount);
protected abstract double calculateFee(double amount);
// 通用方法
protected void logTransaction(String account, double amount, double fee) {
System.out.println("记录交易:" + account + " 取款" + amount + "元,手续费" + fee + "元");
}
// 钩子方法
protected boolean needSendSMS() {
return true;
}
protected void sendSMS(String message) {
System.out.println("发送短信通知:" + message);
}
}
具体银行类
// 普通银行取款
public class NormalBank extends BankTransaction {
@Override
protected boolean verifyAccount(String account) {
System.out.println("普通银行验证账户:" + account);
return account.startsWith("SAV");
}
@Override
protected boolean verifyBalance(String account, double amount) {
System.out.println("普通银行检查余额");
// 假设余额充足
return amount <= 10000;
}
@Override
protected void executeWithdrawal(String account, double amount) {
System.out.println("普通银行执行取款:" + amount + "元");
}
@Override
protected double calculateFee(double amount) {
// 普通银行手续费1%
return amount * 0.01;
}
@Override
protected boolean needSendSMS() {
return true;
}
}
// VIP银行取款
public class VIPBank extends BankTransaction {
@Override
protected boolean verifyAccount(String account) {
System.out.println("VIP银行验证账户:" + account);
return account.startsWith("VIP");
}
@Override
protected boolean verifyBalance(String account, double amount) {
System.out.println("VIP银行检查余额");
// VIP客户可透支
return amount <= 100000;
}
@Override
protected void executeWithdrawal(String account, double amount) {
System.out.println("VIP银行执行取款:" + amount + "元");
}
@Override
protected double calculateFee(double amount) {
// VIP客户免手续费
return 0;
}
// 覆盖钩子方法
@Override
protected boolean needSendSMS() {
return false; // VIP客户不需要短信通知
}
}
测试代码
public class BankDemo {
public static void main(String[] args) {
System.out.println("=== 普通银行取款 ===");
BankTransaction normalBank = new NormalBank();
normalBank.withdraw("SAV001", 1000);
System.out.println("\n=== VIP银行取款 ===");
BankTransaction vipBank = new VIPBank();
vipBank.withdraw("VIP001", 5000);
}
}
模板方法模式的优势
- 代码复用:公共算法骨架在父类中实现一次,子类只实现差异部分
- 控制流程:算法流程由父类控制,子类无法改变流程顺序
- 扩展方便:通过钩子方法,子类可以灵活地插入自定义逻辑
- 符合开闭原则:新增功能时,只需创建新的子类,不需要修改父类
适用场景
- 多个子类有共同的操作步骤和算法
- 重要的、复杂的算法集中在父类中
- 想让子类实现算法的可变部分,保持算法的整体结构不变
- 需要通过钩子方法控制子类的扩展点
模板方法模式非常适合处理那些有固定流程,但具体步骤实现不同的业务场景,如业务流程、数据处理、框架设计等。