My App

模版方法

提供一个方法作为完成某类功能的“固定模板”,模板方法里把整体步骤按顺序封装好,但允许子类通过重写某些“钩子方法 / 抽象方法”来自定义部分细节。

解决什么问题:

  • 提高代码复用性:把一类算法/业务流程中不变的部分固定在父类模板方法里,避免在每个子类中重复编写流程代码。
  • 保留扩展点:把变化的步骤设计成抽象方法或可重写的方法,交给子类去实现,从而在不改变整体流程的前提下扩展行为。
  • 让调用者面向抽象编程:上层代码只调用模板方法,不关心具体是哪一个子类,实现“对扩展开放,对修改关闭”。

怎么写:

实现步骤可以记成三句话:

  1. 在抽象父类中定义一个模板方法:模板方法中按固定顺序调用若干步骤方法(有些是具体的,有些是抽象的),通常把模板方法声明为 final,禁止子类改动整体流程
  2. 在抽象父类中定义抽象方法 / 钩子方法:这些方法只给出“要做什么”的规范,不写具体实现,相当于留给子类的插槽。
  3. 在子类中重写抽象方法 / 钩子方法:根据自己的需求实现差异化逻辑,但整体调用流程仍由父类模板方法控制。

使用场景:

  • 需要在多个子类之间共享相同的处理流程,但某些步骤的实现细节不同;
  • 希望把“算法框架”固化在父类中,只允许子类修改其中的某些步骤;
  • 典型例子:文档生成流程、报表导出流程、钩子型回调流程、Spring 中的各种 XXXTemplate

示例:

// 抽象父类:定义写作文的模板
public abstract class People {

    // 模板方法:固定作文的大致结构
    public final void write() {   // 通常加 final,防止子类修改整体流程
        System.out.println("《我的爸爸》");
        System.out.println("第一段:我爸爸是一个好人,我特别喜欢他,他对我很好...");

        // 变化的部分:每个子类写自己眼中的爸爸
        writeMain();

        System.out.println("最后一段:我爸爸真好,你有这样的爸爸吗?");
    }

    // 抽象方法:留给子类实现具体内容
    public abstract void writeMain();
}

// 子类 1:学生视角
public class Student extends People {
    @Override
    public void writeMain() {
        System.out.println("中间段:我爸爸很牛逼,是个管理者,我开车不用看红绿灯。");
    }
}

// 子类 2:老师视角
public class Teacher extends People {
    @Override
    public void writeMain() {
        System.out.println("中间段:我爸爸经常让我站在这里别动,他要去买几斤桔子~~");
    }
}

// 测试类:调用模板方法
public class Test {
    public static void main(String[] args) {
        People s = new Student();
        s.write();   // 调用同一个模板方法,输出学生版作文

        People t = new Teacher();
        t.write();   // 调用同一个模板方法,输出老师版作文
    }
}

小结:模板方法模式 = 父类固定流程 + 子类重写步骤
不变的流程写在父类,变化的细节交给子类,从而在保证结构统一的前提下,实现灵活多样的行为。

On this page