Featured image of post Interpreterパターン調査ドキュメント

Interpreterパターン調査ドキュメント

振る舞いパターンInterpreterについての調査結果。概要、用途、サンプル、利点・欠点を整理

Interpreterパターン調査ドキュメント

調査目的

GoF(Gang of Four)デザインパターンの振る舞いパターンに分類されるInterpreterパターンについて調査を行い、概要、用途、サンプル、利点・欠点を整理する。

  • 調査対象: Interpreterパターン(振る舞いパターン)
  • 想定読者: デザインパターンを学習中のソフトウェアエンジニア
  • 調査実施日: 2025年12月31日

1. Interpreterパターンの概要

1.1 定義

要点:

  • Interpreterパターンは、言語の文法を表現するクラス階層を定義し、その文法に従って文(文章・式)を解釈するインタプリタを提供するパターンである
  • 各クラスが文法規則を1つずつカプセル化し、これらを組み合わせて複雑な式を解釈・処理できる
  • 特定のコードではなく、文法規則をオブジェクト構造(抽象構文木)として表現する設計アイデアである

根拠:

  • GoF書籍「Design Patterns: Elements of Reusable Object-Oriented Software」において、振る舞いパターンの1つとして定義されている
  • 「言語の文法表現を定義し、その文法に従って文を解釈するインタプリタを提供する」と記載

出典:

信頼度: 高


1.2 パターンの構造

構成要素(参加者):

Interpreterパターンは以下の5つの主要なコンポーネントで構成される。

コンポーネント役割
AbstractExpressionすべての式に共通のinterpret(context)メソッドを宣言する抽象クラスまたはインターフェースExpressionインターフェース
TerminalExpression文法の終端記号(リーフノード)を実装。最も単純な要素を表現数値、変数、リテラル
NonterminalExpression文法の非終端記号(複合ノード)を実装。他の式を組み合わせて解釈演算子(+、-、AND、OR)
Contextインタプリタ全体で共有される情報を保持変数テーブル、入力文字列
Client抽象構文木(AST)を構築し、ルートノードのinterpretを呼び出すメインプログラム

クラス構造図(概念):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Client ──────────────────────────────────────────────────────────────
    ├── Context(共有情報)
    └── AbstractExpression(抽象/インターフェース)
            ├── TerminalExpression(終端:リーフ)
            └── NonterminalExpression(非終端:複合)
                    └── 子Expression(再帰的に構成)

出典:

信頼度: 高


2. 用途・適用場面

2.1 主な用途

要点:

Interpreterパターンは以下のような場面で適用される。

用途説明具体例
数式評価器数学的な式を解析・評価電卓、スプレッドシートの数式、科学計算ツール
ドメイン固有言語(DSL)アプリケーション固有のミニ言語を実装ビジネスルールエンジン、設定ファイル形式
クエリ言語SQL風の問い合わせを解釈Excel検索、簡易データベースクエリ
正規表現エンジンパターンマッチングの構文を解釈入力検証、テキスト検索
テンプレートエンジン変数置換やループの構文を処理HTML生成(Jinja2、Liquid等)
設定・スクリプト解析カスタム設定ファイルやスクリプトを処理Makefile、Infrastructure as Code

根拠:

  • 多くの技術文献で、上記の適用例が報告されている
  • GoF書籍においても、正規表現エンジンが代表例として挙げられている

出典:

信頼度: 高


2.2 適用の判断基準

使用すべき場面:

  • シンプルで安定した文法を持つ言語を解釈する必要がある場合
  • 問題が「言語の文」として自然に表現できる場合
  • 文法の拡張(新しい式の追加)が頻繁に発生する場合
  • 既存コードを変更せずに新しい文法規則を追加したい場合

使用を避けるべき場面:

  • 文法が複雑で、多くの規則を持つ場合(SQLやプログラミング言語など)
  • パフォーマンスが重要な場合(再帰的な解釈はオーバーヘッドを生む)
  • より適切なパーサージェネレーター(ANTLR、yacc等)が利用可能な場合

出典:

信頼度: 高


3. サンプルコード

3.1 Javaによる論理式インタプリタの例

以下は、論理式(AND/OR)を解釈するインタプリタの実装例である。

3.1.1 Expressionインターフェース(AbstractExpression)

1
2
3
4
// Java 11+
public interface Expression {
    boolean interpret(String context);
}

3.1.2 TerminalExpression(終端式)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Java 11+
public class TerminalExpression implements Expression {
    private String data;

    public TerminalExpression(String data) {
        this.data = data;
    }

    @Override
    public boolean interpret(String context) {
        return context.contains(data);
    }
}

3.1.3 NonterminalExpression(非終端式:AND/OR)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Java 11+
public class AndExpression implements Expression {
    private Expression expr1;
    private Expression expr2;

    public AndExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) && expr2.interpret(context);
    }
}

public class OrExpression implements Expression {
    private Expression expr1;
    private Expression expr2;

    public OrExpression(Expression expr1, Expression expr2) {
        this.expr1 = expr1;
        this.expr2 = expr2;
    }

    @Override
    public boolean interpret(String context) {
        return expr1.interpret(context) || expr2.interpret(context);
    }
}

3.1.4 Client(使用例)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Java 11+
public class InterpreterDemo {
    public static void main(String[] args) {
        // 終端式を作成
        Expression isJava = new TerminalExpression("Java");
        Expression isPattern = new TerminalExpression("Pattern");

        // 非終端式を作成(Java AND Pattern)
        Expression isJavaPattern = new AndExpression(isJava, isPattern);

        // コンテキスト(入力文字列)
        String context = "Java Design Pattern";

        // 解釈を実行
        System.out.println("Context: " + context);
        System.out.println("Java AND Pattern? " + isJavaPattern.interpret(context));
        // 出力: Java AND Pattern? true

        // OR式の例
        Expression isPython = new TerminalExpression("Python");
        Expression isJavaOrPython = new OrExpression(isJava, isPython);
        System.out.println("Java OR Python? " + isJavaOrPython.interpret(context));
        // 出力: Java OR Python? true
    }
}

出典:

信頼度: 高


3.2 Pythonによる論理式インタプリタの例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# Python 3.8+
from abc import ABC, abstractmethod

# AbstractExpression
class Expression(ABC):
    @abstractmethod
    def interpret(self, context: str) -> bool:
        pass

# TerminalExpression
class TerminalExpression(Expression):
    def __init__(self, data: str):
        self.data = data

    def interpret(self, context: str) -> bool:
        return self.data in context

# NonterminalExpression: AND
class AndExpression(Expression):
    def __init__(self, expr1: Expression, expr2: Expression):
        self.expr1 = expr1
        self.expr2 = expr2

    def interpret(self, context: str) -> bool:
        return self.expr1.interpret(context) and self.expr2.interpret(context)

# NonterminalExpression: OR
class OrExpression(Expression):
    def __init__(self, expr1: Expression, expr2: Expression):
        self.expr1 = expr1
        self.expr2 = expr2

    def interpret(self, context: str) -> bool:
        return self.expr1.interpret(context) or self.expr2.interpret(context)

# Client
if __name__ == "__main__":
    context = "Java Design Pattern"

    is_java = TerminalExpression("Java")
    is_pattern = TerminalExpression("Pattern")

    # Java AND Pattern
    is_java_pattern = AndExpression(is_java, is_pattern)
    print(f"Java AND Pattern? {is_java_pattern.interpret(context)}")  # True

    # Java OR Python
    is_python = TerminalExpression("Python")
    is_java_or_python = OrExpression(is_java, is_python)
    print(f"Java OR Python? {is_java_or_python.interpret(context)}")  # True

出典:

信頼度: 高


3.3 数式評価器の概念例

数式 5 + 3 * 2 を評価する場合の構造:

1
2
3
4
5
6
        [Add]
       /    \
    [Num]   [Mul]
      5     /    \
        [Num]   [Num]
          3       2

この抽象構文木(AST)を再帰的にinterpretすることで、結果 11 を得る。


4. 利点・欠点

4.1 利点

利点説明
拡張性が高い新しい文法規則を追加する際、新しいExpressionクラスを追加するだけで良い。既存コードの変更が不要
関心の分離文法規則と解釈ロジックが明確に分離され、コードの理解・保守が容易
再利用性文法規則をカプセル化したクラスは、異なるシステムや場面で再利用可能
シンプルな文法に最適数式、検索クエリ、シンプルなスクリプト言語など、単純な文法の実装に適している
DSL実装に有効ドメイン固有言語(DSL)、設定ファイル形式、ルールエンジンの実装に適している
オブジェクト指向的文法規則をクラス階層として表現するため、オブジェクト指向設計の原則に沿っている

出典:

信頼度: 高


4.2 欠点

欠点説明
複雑な文法には不向き文法が複雑になると、クラス数が爆発的に増加し、管理が困難になる
パフォーマンスの問題再帰的な解釈とオブジェクト生成により、パフォーマンスが低下する可能性がある
クラスの増殖各文法規則に対応するクラスが必要なため、多数の小さなクラスが生成される
保守の難しさ大規模な文法を持つ場合、クラス階層の保守が困難になる
パーサーの責任がクライアントに抽象構文木(AST)の構築はクライアント側の責任となり、複雑になりやすい

出典:

信頼度: 高


4.3 利点・欠点サマリー表

観点利点欠点
拡張性新しい式を簡単に追加可能複雑な文法ではクラス数が爆発
パフォーマンス再帰的解釈によるオーバーヘッド
保守性関心の分離により理解しやすい大規模階層の管理が困難
適用範囲シンプルな文法・DSLに最適本格的な言語には不適切

5. 他のパターンとの関係

5.1 関連パターン

パターン関係
Composite抽象構文木(AST)はCompositeパターンの構造を持つ。NonterminalExpressionがComposite、TerminalExpressionがLeafに対応
Iterator抽象構文木を走査する際にIteratorパターンを使用できる
Visitor式に対する操作(評価以外の処理)を追加する場合、Visitorパターンと組み合わせる
Flyweight終端記号が繰り返し出現する場合、Flyweightパターンでインスタンスを共有できる

出典:

信頼度: 高


6. 実世界での適用例

6.1 現実のプロダクトでの使用例

プロダクト/技術適用場面
正規表現エンジン正規表現構文の解釈とパターンマッチング
SQL処理系SQLクエリの解析と実行(簡易的なもの)
Spring Expression Language (SpEL)Spring Frameworkの式言語
ANTLR文法定義からパーサーを生成(Interpreterパターンの発展形)
計算機アプリケーション数式の入力と評価
テンプレートエンジンJinja2、Liquid、Twigなど

出典:

信頼度: 高


7. 内部リンク調査

7.1 関連記事(デザインパターン・オブジェクト指向)

リポジトリ内のデザインパターン関連コンテンツ:

ファイルパス内部リンク関連度
/content/warehouse/design-patterns-overview.md(調査ドキュメント)
/content/warehouse/design-patterns-research.md(調査ドキュメント)
/content/post/2021/10/31/191008.md/2021/10/31/191008/中(Moo OOP)

8. 参考文献・参考サイト

8.1 公式書籍・定番書籍

書籍名著者備考
Design Patterns: Elements of Reusable Object-Oriented SoftwareErich Gamma, Richard Helm, Ralph Johnson, John VlissidesGoF原典、Interpreterパターンの定義元
Head First Design Patterns (2nd Edition)Eric Freeman, Elisabeth Robson初心者向け、視覚的解説
Dive Into Design PatternsAlexander ShvetsRefactoring Guru著者

8.2 信頼性の高いWebリソース

リソース名URL特徴
Refactoring Guruhttps://refactoring.guru/design-patterns/interpreter視覚的解説、多言語コード例
GeeksforGeekshttps://www.geeksforgeeks.org/system-design/interpreter-design-pattern/網羅的解説
Baeldunghttps://www.baeldung.com/java-interpreter-patternJava実装例
SourceMakinghttps://sourcemaking.com/design_patterns/interpreterパターン詳細解説
Java Design Patternshttps://java-design-patterns.com/patterns/interpreter/オープンソース実装例

8.3 GitHub上の実装例

リポジトリ言語URL
iluwatar/java-design-patternsJavahttps://github.com/iluwatar/java-design-patterns
RefactoringGuru/design-patterns-pythonPythonhttps://github.com/RefactoringGuru/design-patterns-python
faif/python-patternsPythonhttps://github.com/faif/python-patterns

9. 調査結果のサマリー

9.1 主要な発見

  1. Interpreterパターンは言語解釈に特化: 文法規則をクラス階層として表現し、抽象構文木(AST)を再帰的に解釈するパターンである
  2. シンプルな文法に最適: 複雑な文法には不向きで、DSL、数式評価、簡易クエリ言語などに適用される
  3. 拡張性と保守性のトレードオフ: 新しい式の追加は容易だが、文法が複雑化するとクラス数が増大し保守が困難になる
  4. Compositeパターンとの密接な関係: 抽象構文木の構造はCompositeパターンそのものである

9.2 適用判断のガイドライン

条件推奨
シンプルで安定した文法Interpreterパターンを適用
複雑で頻繁に変更される文法パーサージェネレーター(ANTLR等)を検討
パフォーマンスが重要他のアプローチを検討
DSL・ルールエンジンの実装Interpreterパターンが有効

調査完了: 2025年12月31日

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。