JavaScript设计模式「基于ES2024」:行为型模式-模板方法模式

44 阅读2分钟

模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

// 抽象类:数据挖掘器
class DataMiner {
    // 模板方法
    mine(path) {
        const file = this.openFile(path);
        const rawData = this.extractData(file);
        const data = this.parseData(rawData);
        const analysis = this.analyzeData(data);
        this.sendReport(analysis);
        this.closeFile(file);
    }

    // 具体方法
    openFile(path) {
        console.log(`Opening file: ${path}`);
        return { path };
    }

    closeFile(file) {
        console.log(`Closing file: ${file.path}`);
    }

    sendReport(analysis) {
        console.log("Sending report...");
        console.log(analysis);
    }

    // 抽象方法(在JavaScript中通过抛出错误来模拟)
    extractData(file) {
        throw new Error("extractData must be implemented by subclasses");
    }

    parseData(rawData) {
        throw new Error("parseData must be implemented by subclasses");
    }

    analyzeData(data) {
        throw new Error("analyzeData must be implemented by subclasses");
    }
}

// 具体类:CSV数据挖掘器
class CSVDataMiner extends DataMiner {
    extractData(file) {
        console.log(`Extracting data from CSV file: ${file.path}`);
        return "raw,csv,data";
    }

    parseData(rawData) {
        console.log("Parsing CSV data");
        return ["parsed", "csv", "data"];
    }

    analyzeData(data) {
        console.log("Analyzing CSV data");
        return `CSV Analysis Result: ${data.join(", ")}`;
    }
}

// 具体类:PDF数据挖掘器
class PDFDataMiner extends DataMiner {
    extractData(file) {
        console.log(`Extracting data from PDF file: ${file.path}`);
        return "raw pdf data";
    }

    parseData(rawData) {
        console.log("Parsing PDF data");
        return { type: "pdf", content: "parsed pdf data" };
    }

    analyzeData(data) {
        console.log("Analyzing PDF data");
        return `PDF Analysis Result: ${data.content}`;
    }
}

// 客户端代码
function clientCode(dataMiner, filePath) {
    console.log("Client: Starting data mining process...");
    dataMiner.mine(filePath);
}

// 使用示例
console.log("Mining CSV file:");
clientCode(new CSVDataMiner(), "data.csv");

console.log("\nMining PDF file:");
clientCode(new PDFDataMiner(), "report.pdf");

实现思路

  1. DataMiner 抽象类

    • 定义了 mine 方法,这是模板方法,它规定了数据挖掘的算法骨架。
    • 包含了一些具体方法(openFile, closeFile, sendReport),这些方法在所有子类中都是通用的。
    • 定义了抽象方法(extractData, parseData, analyzeData),这些方法需要由子类实现。
  2. 具体类 CSVDataMinerPDFDataMiner

    • 继承自 DataMiner 类。
    • 实现了抽象方法,提供了特定文件类型的具体实现。
  3. 客户端代码

    • 使用具体的数据挖掘器对象,调用模板方法 mine
  4. 模板方法 mine

    • 定义了算法的骨架,按顺序调用各个步骤。
    • 一些步骤由基类实现,一些则推迟到子类中实现。

优点

  • 代码复用:通用的步骤在父类中实现,避免了重复代码。
  • 扩展性:可以轻松添加新的数据挖掘器类型,而不影响现有代码。
  • 控制反转:父类调用子类的操作,而不是相反。
  • 封装不变部分:将不变的部分封装在父类中,将可变部分留给子类实现。