模板方法设计模式(Template Method Pattern)

模板方法模式是 23 种设计模式中的一种行为型模式,它的核心思想是定义一个算法的骨架,将一些步骤延迟到子类中实现。这样可以在不改变算法整体结构的情况下,让子类重新定义算法中的某些特定步骤。

核心原理

抽象模板类(Abstract Class)
定义算法的骨架,包含一个模板方法(template method)
模板方法中调用一系列基本方法(primitive operations)
基本方法可以是抽象的(由子类实现)或具体的(父类提供默认实现)
具体子类(Concrete Class)
实现抽象模板类中的抽象方法
可以选择重写父类中的具体方法(如果允许)
不改变模板方法定义的算法结构
钩子方法(Hook Method)
父类中提供默认实现(通常为空)
子类可以根据需要重写,用于控制算法流程;

模板方法模式的关键是好莱坞原则:“不要调用我们,我们会调用你”,即父类控制流程,子类提供实现。

Java 实践示例

下面以 “制作饮品” 为例实现模板方法模式:
所有饮品的制作流程大致相同(模板方法)
具体步骤(如冲泡、添加调料)因饮品而异

package com.example.demo;

public class TemplateMethodPattern {
    public static void main(String[] args) {
        Beverage coffee = new Coffee();
        System.out.println("制作咖啡:");
        coffee.makeBeverage();

        System.out.println("\n制作茶:");
        Beverage tea = new Tea();
        tea.makeBeverage();
    }

    // 抽象模板类:饮品
    public abstract static class Beverage {
        // 模板方法:定义制作饮品的流程,用final修饰防止子类重写
        public final void makeBeverage() {
            boilWater();       // 煮水
            brew();            // 冲泡(抽象方法,子类实现)
            pourInCup();       // 倒入杯中
            if (needCondiments()) { // 钩子方法:是否需要添加调料
                addCondiments();   // 添加调料(抽象方法,子类实现)
            }
        }

        // 具体方法:煮水(所有饮品通用)
        private void boilWater() {
            System.out.println("煮水");
        }

        // 具体方法:倒入杯中(所有饮品通用)
        private void pourInCup() {
            System.out.println("倒入杯中");
        }

        // 抽象方法:冲泡(子类实现具体饮品的冲泡方式)
        protected abstract void brew();

        // 抽象方法:添加调料(子类实现具体饮品的调料)
        protected abstract void addCondiments();

        // 钩子方法:默认需要添加调料,子类可重写
        protected boolean needCondiments() {
            return true;
        }
    }

    // 具体子类:咖啡
    public static class Coffee extends Beverage {
        @Override
        protected void brew() {
            System.out.println("用沸水冲泡咖啡");
        }

        @Override
        protected void addCondiments() {
            System.out.println("添加牛奶和糖");
        }

        // 重写钩子方法:允许用户选择是否加调料
        @Override
        protected boolean needCondiments() {
            // 实际应用中可以在这里添加用户输入逻辑
            return false; // 假设用户不要调料
        }
    }

    // 具体子类:茶
    public static class Tea extends Beverage {
        @Override
        protected void brew() {
            System.out.println("用沸水浸泡茶叶");
        }

        @Override
        protected void addCondiments() {
            System.out.println("添加柠檬");
        }

        // 不重写钩子方法,使用父类默认实现(需要添加调料)
    }
}

代码解析

  • Beverage 抽象类:
    makeBeverage() 是模板方法,定义了制作饮品的固定流程
    包含具体方法(boilWater()、pourInCup())和抽象方法(brew()、addCondiments())
    提供钩子方法 needCondiments() 控制是否添加调料
  • 具体实现类:
    Coffee 和 Tea 分别实现了抽象方法,提供了各自的冲泡和添加调料方式
    Coffee 重写了钩子方法,改变了默认行为(不添加调料)

应用场景

框架设计:如 Spring 中的JdbcTemplate,定义了数据库操作的流程,将具体 SQL 执行延迟到子类
生命周期管理:如 Servlet 的init()、service()、destroy()方法构成的生命周期模板
算法步骤固定:如排序算法的整体流程固定,但具体比较方式可由子类实现
报表生成:固定报表的整体结构,具体数据填充由子类实现

模板方法模式的优势

模板方法模式的优势在于代码复用和算法结构的稳定性,同时通过钩子方法提供了灵活的扩展点

更多推荐