模板方法(Template Method)
意图
定义一个操作中的算法骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变算法结构的情况下,重新定义算法中的某些特定步骤。
UML 图
优点
- 代码复用:将公共行为移到父类中,避免代码重复
- 封装不变部分:固定算法结构,保护核心算法不被修改
- 扩展性好:通过子类扩展具体实现,符合开闭原则
- 便于维护:算法修改只需在父类中进行,子类不受影响
- 提高灵活性:子类可以灵活实现特定步骤,而不影响整体结构
缺点
- 限制扩展性:算法框架固定,可能限制子类的灵活性
- 增加系统复杂度:每个不同实现都需要一个子类,可能导致类数量增加
- 违反里氏替换原则:如果子类对模板方法进行重写,可能破坏父类定义的行为
- 调试困难:模板方法中的步骤调用可能在多个子类中实现,调试较复杂
- 可能产生过多抽象:如果步骤划分过细,可能导致系统过于抽象
代码示例
以人类和机器人执行任务的不同方式为例:
1. 抽象模板类 (Abstract Template Class)
// 抽象任务模板
public abstract class TaskTemplate {private String taskName;public TaskTemplate(String taskName) {this.taskName = taskName;}// 模板方法 - 定义算法骨架 (final防止子类重写)public final void executeTask() {System.out.println("🚀 开始执行任务: " + taskName);prepareEnvironment();performCoreTask();cleanup();generateReport();System.out.println("✅ 任务完成: " + taskName + "\n");}// 具体方法 - 通用实现private void prepareEnvironment() {System.out.println("🔧 准备执行环境...");}// 抽象方法 - 由子类实现protected abstract void performCoreTask();// 钩子方法 - 默认实现,子类可选择重写protected void cleanup() {System.out.println("🧹 执行默认清理操作...");}// 具体方法 - 通用实现private void generateReport() {System.out.println("📊 生成任务报告...");}public String getTaskName() {return taskName;}
}
2. 具体实现类 (Concrete Implementations)
// 人类任务执行者
public class HumanTaskExecutor extends TaskTemplate {public HumanTaskExecutor(String taskName) {super(taskName);}@Overrideprotected void performCoreTask() {System.out.println("👤 人类正在执行任务:");System.out.println(" 💡 运用创造力和直觉");System.out.println(" 🤝 进行团队协作");System.out.println(" ❤️ 融入情感因素");}@Overrideprotected void cleanup() {System.out.println("🧽 人类进行细致的手工清理...");}
}// 机器人任务执行者
public class RobotTaskExecutor extends TaskTemplate {public RobotTaskExecutor(String taskName) {super(taskName);}@Overrideprotected void performCoreTask() {System.out.println("🤖 机器人正在执行任务:");System.out.println(" ⚡ 高速精确计算");System.out.println(" 📏 严格按照程序执行");System.out.println(" 🔄 重复性工作无误差");}@Overrideprotected void cleanup() {System.out.println("🛠️ 机器人进行自动化清理...");}
}// 混合任务执行者 - 展示钩子方法的使用
public class HybridTaskExecutor extends TaskTemplate {private boolean needsSpecialCleanup;public HybridTaskExecutor(String taskName, boolean needsSpecialCleanup) {super(taskName);this.needsSpecialCleanup = needsSpecialCleanup;}@Overrideprotected void performCoreTask() {System.out.println("👥 人机协作执行任务:");System.out.println(" 🧠 人类负责决策和创意");System.out.println(" 💻 机器人负责计算和执行");System.out.println(" 🤝 完美协作完成任务");}@Overrideprotected void cleanup() {if (needsSpecialCleanup) {System.out.println("🌟 执行特殊的协作清理流程...");} else {super.cleanup(); // 使用父类的默认实现}}
}
3. 客户端代码
public class TemplateMethodDemo {public static void main(String[] args) {System.out.println("=== 模板方法模式演示 ===\n");// 创建不同类型的任务执行者TaskTemplate humanTask = new HumanTaskExecutor("创意设计任务");TaskTemplate robotTask = new RobotTaskExecutor("数据分析任务");TaskTemplate hybridTask1 = new HybridTaskExecutor("复杂项目任务", false);TaskTemplate hybridTask2 = new HybridTaskExecutor("敏感数据处理任务", true);// 执行任务 - 相同的模板方法,不同的具体实现System.out.println("1. 人类执行任务:");humanTask.executeTask();System.out.println("2. 机器人执行任务:");robotTask.executeTask();System.out.println("3. 人机协作任务 (默认清理):");hybridTask1.executeTask();System.out.println("4. 人机协作任务 (特殊清理):");hybridTask2.executeTask();// 演示模板方法的灵活性System.out.println("=== 动态任务执行 ===");TaskTemplate[] tasks = {new HumanTaskExecutor("紧急创意任务"),new RobotTaskExecutor("批量处理任务"),new HybridTaskExecutor("综合解决方案", true)};for (TaskTemplate task : tasks) {task.executeTask();}}
}
在Java标准库中的应用
模板方法模式在Java标准库中的广泛应用:
- InputStream/OutputStream
// InputStream 中的模板方法
public abstract class InputStream {// 模板方法public int read(byte[] b, int off, int len) throws IOException {// ... 算法骨架int c = read(); // 调用抽象方法// ... 后续处理return c;}// 抽象方法 - 由子类实现public abstract int read() throws IOException;
}
- AbstractList/AbstractSet
// AbstractList 中的模板方法
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {// 模板方法public boolean addAll(int index, Collection<? extends E> c) {// ... 算法骨架for (E e : c) {add(index++, e); // 调用抽象方法}return true;}// 抽象方法 - 由子类实现public abstract void add(int index, E element);
}
- HttpServlet
// HttpServlet 中的模板方法
public abstract class HttpServlet extends GenericServlet {// 模板方法protected void service(HttpServletRequest req, HttpServletResponse resp) {String method = req.getMethod();if (method.equals("GET")) {doGet(req, resp); // 调用具体方法} else if (method.equals("POST")) {doPost(req, resp); // 调用具体方法}// ... 其他HTTP方法}// 由子类实现的具体方法protected void doGet(HttpServletRequest req, HttpServletResponse resp) {// 默认实现}
}
- Java AWT/Swing
// JComponent 中的绘制模板
public abstract class JComponent extends Container {// 模板方法public void paint(Graphics g) {paintComponent(g); // 由子类实现paintBorder(g); // 默认实现paintChildren(g); // 默认实现}// 抽象方法 - 由子类实现protected void paintComponent(Graphics g);
}
总结
模板方法模式通过定义算法的骨架而将一些步骤延迟到子类中,实现了代码复用和扩展性的平衡。在人类和机器人的例子中,我们可以看到:
- 固定流程:所有任务都遵循
准备→执行核心任务→清理→报告
的统一流程 - 灵活实现:人类和机器人以不同的方式执行核心任务和清理工作
- 代码复用:环境准备和报告生成等通用逻辑在父类中实现,避免重复代码
- 易于扩展:添加新的任务执行者只需实现特定的步骤,而不影响整体算法结构
这种模式特别适用于有固定流程但具体实现可能变化的场景,如各种数据处理流程、工作流引擎、游戏循环等。通过合理使用模板方法,可以提高代码的可维护性和可扩展性。