TypeScript设计模式:工厂方法模式

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,用于定义一个创建对象的接口,但将实际的实例化过程延迟到子类中实现。这允许子类决定实例化哪种具体类,从而实现灵活的对象创建。

什么是工厂方法模式?

工厂方法模式的核心是通过抽象工厂类定义一个创建对象的方法(工厂方法),由子类实现具体的对象创建逻辑。这样可以实现:

  • 解耦:客户端代码与具体类的实例化过程分离,只依赖抽象接口。
  • 扩展性:通过添加新的子类,可以轻松支持新的产品类型。
  • 单一职责:将对象创建逻辑从业务逻辑中分离,增强代码清晰度。

在 TypeScript 中,工厂方法模式通过接口和抽象类结合类型系统,确保创建的对象符合预期类型。

工厂方法模式的结构

工厂方法模式通常包含以下几个角色:

  1. Product(产品接口):定义工厂方法创建的对象的接口。
  2. ConcreteProduct(具体产品):实现产品接口,定义具体的对象。
  3. Creator(创建者接口/抽象类):声明工厂方法,返回 Product 类型。
  4. ConcreteCreator(具体创建者):实现工厂方法,创建具体产品实例。

优点

  • 解耦合:客户端无需知道具体类的实现,只通过接口交互。
  • 扩展性:添加新产品只需实现新产品类和对应的工厂类。
  • 类型安全:TypeScript 的类型系统确保工厂方法返回正确的对象类型。
  • 单一职责:创建逻辑与使用逻辑分离,符合设计原则。

适用场景

  • 当对象的创建过程复杂或需要根据条件选择具体类型时。
  • 需要支持多种类似对象,且可能在未来扩展新类型时(如文档解析器、UI 组件生成器)。
  • 希望将对象的创建与使用分离,提升代码可维护性。

简单的模拟代码介绍

以下是一个简单的 TypeScript 示例,模拟一个文档生成器的工厂方法模式。我们定义一个文档接口和工厂类,不同类型的文档(如 PDF 和 Word)通过具体工厂创建。

typescript 复制代码
// 产品接口
interface Document {
  generate(): string;
}

// 具体产品:PDF 文档
class PDFDocument implements Document {
  generate(): string {
    return "Generating PDF document";
  }
}

// 具体产品:Word 文档
class WordDocument implements Document {
  generate(): string {
    return "Generating Word document";
  }
}

// 创建者抽象类
abstract class DocumentCreator {
  // 工厂方法
  abstract createDocument(): Document;

  // 使用工厂方法的操作
  generateDocument(): string {
    const document = this.createDocument();
    return document.generate();
  }
}

// 具体创建者:PDF 文档工厂
class PDFDocumentCreator extends DocumentCreator {
  createDocument(): Document {
    return new PDFDocument();
  }
}

// 具体创建者:Word 文档工厂
class WordDocumentCreator extends DocumentCreator {
  createDocument(): Document {
    return new WordDocument();
  }
}

// 客户端代码
function main() {
  const pdfCreator = new PDFDocumentCreator();
  console.log("Creating PDF:");
  console.log(pdfCreator.generateDocument());

  console.log("\nCreating Word:");
  const wordCreator = new WordDocumentCreator();
  console.log(wordCreator.generateDocument());
}

main();

运行结果

运行以上代码,将输出:

javascript 复制代码
Creating PDF:
Generating PDF document

Creating Word:
Generating Word document

这个模拟示例展示了工厂方法模式的核心:通过抽象工厂方法(createDocument)和具体工厂类(PDFDocumentCreatorWordDocumentCreator)分离创建逻辑,支持不同文档类型的生成。

AI知识库文件解析的实际应用示例

在 AI 知识库管理中,工厂方法模式常用于根据文件类型动态创建适当的解析器,以处理不同格式的文件(如 Markdown、PDF、Word)。客户端只需调用工厂方法,无需了解具体解析器的实现。以下是一个 Node.js 示例,使用 TypeScript 实现一个文件解析器工厂,支持解析 Markdown (.md)、PDF (.pdf) 和 Word (.docx) 文件,提取结构化内容(如标题和段落)并输出为 JSON。我们使用外部库(marked for Markdown、pdf-parse for PDF、mammoth for Word),需安装(npm install marked pdf-parse mammoth)。

实现示例

定义统一的内容模型和解析器接口,工厂方法根据文件扩展名创建对应的解析器。

typescript 复制代码
import * as fs from 'fs/promises';
import * as path from 'path';
import { marked } from 'marked'; // 用于 Markdown 解析
import pdfParse from 'pdf-parse'; // 用于 PDF 解析
import mammoth from 'mammoth'; // 用于 Word 解析

// 定义统一的内容模型
interface ContentSection {
  title: string;
  paragraph: string;
}

// 产品接口:文件解析器
interface FileParser {
  parse(filePath: string): Promise<ContentSection[]>;
}

// 具体产品:Markdown 解析器
class MarkdownFileParser implements FileParser {
  async parse(filePath: string): Promise<ContentSection[]> {
    console.log(`Parsing Markdown file: ${filePath}`);
    const content = await fs.readFile(filePath, 'utf-8');
    const tokens = marked.lexer(content);
    const sections: ContentSection[] = [];
    let currentTitle = '';
    tokens.forEach(token => {
      if (token.type === 'heading') {
        currentTitle = token.text;
      } else if (token.type === 'paragraph' && currentTitle) {
        sections.push({ title: currentTitle, paragraph: token.text });
        currentTitle = '';
      }
    });
    return sections;
  }
}

// 具体产品:PDF 解析器
class PDFFileParser implements FileParser {
  async parse(filePath: string): Promise<ContentSection[]> {
    console.log(`Parsing PDF file: ${filePath}`);
    const buffer = await fs.readFile(filePath);
    const data = await pdfParse(buffer);
    const lines = data.text.split('\n').filter(line => line.trim());
    const sections: ContentSection[] = [];
    for (let i = 0; i < lines.length; i += 2) {
      sections.push({
        title: lines[i] || 'Untitled',
        paragraph: lines[i + 1] || ''
      });
    }
    return sections;
  }
}

// 具体产品:Word 解析器
class WordFileParser implements FileParser {
  async parse(filePath: string): Promise<ContentSection[]> {
    console.log(`Parsing Word file: ${filePath}`);
    const buffer = await fs.readFile(filePath);
    const result = await mammoth.extractRawText({ buffer });
    const paragraphs = result.value.split('\n\n').filter(p => p.trim());
    return paragraphs.map((p, index) => ({
      title: `Section ${index + 1}`,
      paragraph: p
    }));
  }
}

// 创建者抽象类
abstract class ParserCreator {
  // 工厂方法
  abstract createParser(): FileParser;

  // 使用工厂方法解析并输出
  async parseAndOutput(filePath: string, outputPath: string): Promise<void> {
    const parser = this.createParser();
    const sections = await parser.parse(filePath);
    if (sections.length > 0 && sections.every(s => typeof s.title === 'string' && typeof s.paragraph === 'string')) {
      console.log(`Writing JSON output to ${outputPath}`);
      await fs.writeFile(outputPath, JSON.stringify(sections, null, 2));
    } else {
      throw new Error('Invalid content structure');
    }
  }
}

// 具体创建者:Markdown 解析器工厂
class MarkdownParserCreator extends ParserCreator {
  createParser(): FileParser {
    return new MarkdownFileParser();
  }
}

// 具体创建者:PDF 解析器工厂
class PDFParserCreator extends ParserCreator {
  createParser(): FileParser {
    return new PDFFileParser();
  }
}

// 具体创建者:Word 解析器工厂
class WordParserCreator extends ParserCreator {
  createParser(): FileParser {
    return new WordFileParser();
  }
}

// 工厂方法选择器:根据文件扩展名选择工厂
class ParserFactory {
  static getParserCreator(filePath: string): ParserCreator {
    const ext = path.extname(filePath).toLowerCase();
    switch (ext) {
      case '.md':
        return new MarkdownParserCreator();
      case '.pdf':
        return new PDFParserCreator();
      case '.docx':
        return new WordParserCreator();
      default:
        throw new Error(`Unsupported file extension: ${ext}`);
    }
  }
}

// 客户端代码
async function main() {
  // 假设输入文件存在
  const files = [
    { path: 'knowledge.md', output: 'output_md.json' },
    { path: 'knowledge.pdf', output: 'output_pdf.json' },
    { path: 'knowledge.docx', output: 'output_docx.json' }
  ];

  for (const file of files) {
    try {
      const creator = ParserFactory.getParserCreator(file.path);
      await creator.parseAndOutput(file.path, file.output);
    } catch (error) {
      console.error(`Error processing ${file.path}:`, error);
    }
  }
}

main().catch(console.error);

运行与测试

  1. 准备 :安装依赖(npm install marked pdf-parse mammoth @types/node)并准备测试文件:

    • knowledge.md: # Title\nParagraph text
    • knowledge.pdf: PDF 文件(假设包含简单文本)。
    • knowledge.docx: Word 文件(假设包含段落)。
  2. 运行 :执行 npx ts-node parser.ts(假设文件名为 parser.ts)。

  3. 输出 :生成 JSON 文件(如 output_md.json),包含提取的 sections。

  4. 控制台输出示例

    javascript 复制代码
    Parsing Markdown file: knowledge.md
    Writing JSON output to output_md.json
    Parsing PDF file: knowledge.pdf
    Writing JSON output to output_pdf.json
    Parsing Word file: knowledge.docx
    Writing JSON output to output_docx.json

代码说明

  • 工厂方法createParser 定义在抽象类 ParserCreator 中,由具体工厂实现,创建对应解析器。
  • 产品接口FileParser 定义解析行为,具体解析器(如 MarkdownFileParser)实现逻辑。
  • 工厂选择器ParserFactory 根据文件扩展名动态选择工厂,增强扩展性。
  • 现实场景:在 AI 知识库中,此模式适合动态处理多种文档格式,提取内容用于向量嵌入或搜索索引。

总结

工厂方法模式通过将对象创建延迟到子类,提供了解耦和扩展性。从简单文档生成器到 AI 知识库文件解析示例,展示了工厂方法模式在动态选择解析器场景中的应用。结合 TypeScript 的类型安全和 Node.js 的文件处理,工厂方法模式适用于需要灵活创建对象的场景,如文档处理或组件生成。

相关推荐
恋猫de小郭4 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
牛奔5 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌10 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606111 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX11 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了11 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅11 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅12 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法12 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate