跳转到内容

Java模板方法

来自代码酷


模板方法模式(Template Method Pattern)是行为型设计模式的一种,它定义了一个操作中的算法骨架,将某些步骤延迟到子类中实现。该模式允许子类在不改变算法结构的情况下重新定义算法的某些特定步骤。

概述[编辑 | 编辑源代码]

模板方法模式的核心思想是:

  • 在父类中定义一个算法的框架(即“模板方法”),其中包含一系列步骤
  • 某些步骤可以由父类直接实现(通常是不变的部分)
  • 其他步骤则声明为抽象方法,由子类提供具体实现(通常是可变的部分)

这种模式体现了“好莱坞原则”("Don't call us, we'll call you"),即父类控制流程,子类只需实现特定细节。

结构[编辑 | 编辑源代码]

以下是模板方法模式的UML类图:

classDiagram class AbstractClass { +templateMethod() #primitiveOperation1() #primitiveOperation2() #hook() } class ConcreteClass { #primitiveOperation1() #primitiveOperation2() } AbstractClass <|-- ConcreteClass

  • AbstractClass(抽象类):定义模板方法,其中包含算法的骨架
  • ConcreteClass(具体子类):实现父类中定义的抽象操作

代码示例[编辑 | 编辑源代码]

下面是一个简单的Java实现示例:

// 抽象类定义模板方法
abstract class Game {
    // 模板方法(final防止子类覆盖)
    final void play() {
        initialize();
        startPlay();
        endPlay();
    }
    
    // 具体方法(已有默认实现)
    void initialize() {
        System.out.println("游戏初始化完成");
    }
    
    // 抽象方法(由子类实现)
    abstract void startPlay();
    abstract void endPlay();
}

// 具体子类实现
class Cricket extends Game {
    @Override
    void startPlay() {
        System.out.println("板球比赛开始");
    }
    
    @Override
    void endPlay() {
        System.out.println("板球比赛结束");
    }
}

class Football extends Game {
    @Override
    void startPlay() {
        System.out.println("足球比赛开始");
    }
    
    @Override
    void endPlay() {
        System.out.println("足球比赛结束");
    }
}

// 客户端代码
public class TemplateMethodDemo {
    public static void main(String[] args) {
        Game game = new Cricket();
        game.play();
        
        System.out.println();
        
        game = new Football();
        game.play();
    }
}

输出结果:

游戏初始化完成
板球比赛开始
板球比赛结束

游戏初始化完成
足球比赛开始
足球比赛结束

钩子方法[编辑 | 编辑源代码]

模板方法模式中还可以包含钩子方法(Hook Method),它们是父类中已经实现的方法,但子类可以选择覆盖它们来影响模板方法的行为。

abstract class DataProcessor {
    // 模板方法
    final void process() {
        readData();
        transformData();
        if (needValidation()) {
            validateData();
        }
        saveData();
    }
    
    abstract void readData();
    abstract void transformData();
    abstract void saveData();
    
    // 钩子方法(默认实现)
    boolean needValidation() {
        return true;
    }
    
    void validateData() {
        System.out.println("执行默认验证");
    }
}

实际应用场景[编辑 | 编辑源代码]

模板方法模式在Java中有许多实际应用:

1. Java I/O中的InputStream/OutputStream

  - read()方法是模板方法
  - 具体的子类如FileInputStream实现具体的读取逻辑

2. Servlet生命周期

  - javax.servlet.http.HttpServlet中的service()方法
  - 根据HTTP方法调用doGet()doPost()

3. JUnit测试框架

  - TestCase类中的runBare()方法定义了测试流程
  - 具体测试方法由子类实现

优点与缺点[编辑 | 编辑源代码]

优点:

  • 代码复用:将不变行为移到父类,避免代码重复
  • 扩展性好:通过子类扩展新的行为,符合开闭原则
  • 便于维护:算法结构清晰,易于理解和维护

缺点:

  • 可能导致类的数量增加(每个具体实现需要一个子类)
  • 父类与子类之间的耦合度较高
  • 可能违反里氏替换原则,如果子类对父类的方法进行了不恰当的覆盖

与策略模式的区别[编辑 | 编辑源代码]

模板方法模式和策略模式都用于封装算法,但有以下区别:

模板方法模式 策略模式
使用继承(类之间的关系) 使用组合(对象之间的关系)
在编译时确定算法结构 在运行时切换算法
部分算法由子类实现 整个算法由策略类实现

数学表示[编辑 | 编辑源代码]

模板方法可以形式化表示为: TemplateMethod()=Step1()Step2()Stepn() 其中某些Stepi()由父类实现,其他由子类实现。

总结[编辑 | 编辑源代码]

模板方法模式是一种简单但强大的行为设计模式,特别适用于:

  • 有多个类包含几乎相同的算法,只有少量步骤不同
  • 需要控制子类扩展点的情况
  • 框架设计中定义标准流程

通过合理使用模板方法模式,可以提高代码的复用性和可维护性,同时保持足够的灵活性。