
你有沒有想過,Markdown 是怎麼變成 HTML 的?**粗體** 怎麼變成 <strong>粗體</strong>?
這背後就是 Interpreter Pattern 的思路:定義語法規則 → 解析文本 → 執行轉換。
先講結論
Interpreter Pattern 為一種「語言」定義語法規則,每個規則是一個 class,可以組合使用。適合簡單的 DSL(Domain Specific Language),但複雜語言請用 parser generator,別自己硬幹。
classDiagram class InterpreterRule { <<abstract>> +interpret(context)* Context } class BoldInterpreter { +interpret(context) Context } class ItalicInterpreter { +interpret(context) Context } class MarkdownInterpreter { -rules : InterpreterRule[] +addRule(rule) void +interpret(context) String } InterpreterRule <|-- BoldInterpreter InterpreterRule <|-- ItalicInterpreter MarkdownInterpreter o-- InterpreterRule : 依序執行
實戰:迷你 Markdown 解析器

class InterpreterContext {
constructor(text) { this.text = text; }
getText() { return this.text; }
setText(text) { this.text = text; }
}
class BoldInterpreter {
interpret(context) {
let text = context.getText();
text = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
context.setText(text);
return context;
}
}
class ItalicInterpreter {
interpret(context) {
let text = context.getText();
text = text.replace(/\*(.*?)\*/g, '<em>$1</em>');
context.setText(text);
return context;
}
}
class MarkdownInterpreter {
constructor() { this.rules = []; }
addRule(rule) { this.rules.push(rule); }
interpret(context) {
for (const rule of this.rules) {
rule.interpret(context);
}
return context.getText();
}
}
const interpreter = new MarkdownInterpreter();
interpreter.addRule(new BoldInterpreter()); // 先處理粗體
interpreter.addRule(new ItalicInterpreter()); // 再處理斜體
const context = new InterpreterContext('這是 **粗體** 和 *斜體*');
console.log(interpreter.interpret(context));
// 這是 <strong>粗體</strong> 和 <em>斜體</em>注意規則的順序很重要——如果先處理斜體,**粗體** 會被吃掉(因為 ** 裡面包含 *)。
什麼時候適合用 Interpreter?
- 簡單的 DSL 解析(設定檔語法、查詢語言)
- 規則是可組合的、會成長的
- 語法不會太複雜(規則超過 20 條就該考慮用 parser generator)
什麼時候不該用?
語法複雜的時候。Interpreter Pattern 每個規則一個 class,語法一複雜 class 數量就爆炸。真的要做語言解析,用 PEG.js、ANTLR 這類工具。
Interpreter Pattern 就像翻譯——每個翻譯員負責一種語法,文本經過所有翻譯員之後就變成目標語言了。只是翻譯員太多的時候,翻出來的東西連你自己都看不懂。