设计模式-模版方法

发布于:2025-02-25 ⋅ 阅读:(20) ⋅ 点赞:(0)

解释

在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的。Template 提供了这种情况的一个实现框架Template 模式是采用继承的方式实现这一点:将逻辑(算法)框架放在抽象基类中,并定义好细节的接口,子类中实现细节。

一、应用场景示例:跨平台文件解析

假设需要开发支持Windows/Linux/MacOS的文件解析器,三类系统都需要以下步骤:

  1. 加载二进制文件
  2. 解析文件头
  3. 校验数据有效性
  4. 释放文件句柄

使用模板方法模式:

class FileParser {
public:
    void parse() final {  // 固化流程
        loadBinary();
        parseHeader();
        validate();
        releaseHandle();
    }
protected:
    virtual void loadBinary() = 0;
    virtual void parseHeader() = 0;
    virtual void validate() { /* 默认校验逻辑 */ }
    void releaseHandle() { /* 通用释放逻辑 */ }
};

class WindowsParser : public FileParser {
protected:
    void loadBinary() override { 
        /* Windows特有二进制加载 */ 
    }
    void parseHeader() override { 
        /* PE文件头解析 */ 
    }
    // 继承默认validate()
};

class LinuxParser : public FileParser {
protected:
    void loadBinary() override { 
        /* ELF格式加载 */ 
    }
    void parseHeader() override { 
        /* ELF头解析 */ 
    }
    void validate() override { 
        /* 扩展校验逻辑 */ 
    }
};

不使用模板方法模式的问题代码:

// 各平台独立实现流程控制(违反DRY原则)
class WindowsParser {
public:
    void parse() {
        // 必须重复实现完整流程
        loadBinary();  // Windows实现
        parseHeader(); // Windows实现
        validate();    // 重复默认实现
        releaseHandle(); // 重复通用实现
    }
    // 其他方法同上...
};

class LinuxParser {
public:
    void parse() {
        // 重复流程控制代码
        loadBinary();  // Linux实现
        parseHeader(); // Linux实现
        validate();    // 定制实现
        releaseHandle(); // 重复通用实现
    }
    // 其他方法同上...
};

二、不使用模板模式的缺点分析

  1. 代码冗余:每个子类都需要重复流程控制代码(如releaseHandle())
  2. 维护风险:修改流程时需要修改所有子类(例如新增日志步骤)
  3. 默认行为缺失:无法在基类中提供validate()的默认实现
  4. 接口不一致:容易遗漏步骤(如忘记调用releaseHandle())

三、关键场景对比

场景 使用模板模式 不用模板模式
新增处理步骤 仅修改基类模板方法 需要修改所有实现类
流程异常处理 基类统一添加try-catch块 每个实现类单独处理
性能监控 在模板方法中添加计时逻辑 需在所有parse()方法中插入代码
默认行为覆盖 通过虚函数选择性重写 需要复制粘贴默认代码或继承普通类

四、特定缺陷示例:资源泄漏

// 错误示例:未强制释放资源
class MacParser {
public:
    void parse() {
        loadBinary();
        parseHeader();  // 如果此处抛出异常
        validate();     // 后续代码不会执行
        // 忘记调用releaseHandle()
    }
};

模板方法模式通过固定流程保证:

void FileParser::parse() final {
    try {
        loadBinary();
        parseHeader();
        validate();
    } catch(...) {
        // 统一异常处理
    }
    releaseHandle();  // 确保始终执行
}

结论:当存在多个相似流程的实现时,模板方法模式通过固化算法框架,从根本上避免了流程控制代码的重复和潜在风险。