0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GoFデザインパターン】Interpreter(インタープリター)パターンをJavaで理解する

0
Last updated at Posted at 2026-09-23

はじめに

本記事は、GoFデザインパターン解説シリーズの1つです。

今回は、振る舞いに関するパターンの中のInterpreter(インタープリター)パターンを解説します。

23パターンの中でも、実務での登場頻度は比較的低いものの、「文法規則をクラス構造で表現する」という考え方は、プログラミング言語処理系や設定ファイルのパーサーを理解する上で役立ちます。

解決したい課題

特定の文法規則(ミニ言語)に従った文章を解釈し、実行(評価)したいという場面があります。

例えば、「A AND B」「A OR (B AND C)」のような、簡易的な論理式を評価するミニ言語を実装したいとします。

こうした文法を解釈する処理を、条件分岐や文字列処理だけで直接書こうとすると、文法が複雑になるにつれてコードも急速に複雑化し、保守が困難になります。

Interpreterパターンは、文法の規則(構文要素)ごとに、対応するクラスを用意し、これらを組み合わせて構文木(構造)を作ることで、文章の解釈を「オブジェクトの評価」として表現することで、この問題を解決します。

image.png

クラス構成

  • AbstractExpression(抽象式): 解釈・評価を行うメソッド(interpret())を持つ共通インターフェース
  • TerminalExpression(終端式): それ以上分解できない、文法の末端要素(変数、リテラル値など)を表すクラス
  • NonterminalExpression(非終端式): 複数のExpressionを組み合わせた、複合的な文法規則(AND、OR等の演算子)を表すクラス
  • Context(コンテキスト): 解釈に必要な、変数の値などの情報を保持するクラス

image.png

Javaでの実装例

先ほどの、簡易論理式(AND/OR)を評価するミニ言語を実装してみます。

Context:変数の値を保持するクラス

import java.util.HashMap;
import java.util.Map;

public class Context {
    private final Map<String, Boolean> variables = new HashMap<>();

    public void setVariable(String name, boolean value) {
        variables.put(name, value);
    }

    public boolean getVariable(String name) {
        return variables.getOrDefault(name, false);
    }
}

AbstractExpression:共通インターフェース

public interface Expression {
    boolean interpret(Context context);
}

TerminalExpression:変数を表す終端式

public class VariableExpression implements Expression {
    private final String name;

    public VariableExpression(String name) {
        this.name = name;
    }

    @Override
    public boolean interpret(Context context) {
        return context.getVariable(name);
    }
}

NonterminalExpression:AND・OR・NOTを表す非終端式

public class AndExpression implements Expression {
    private final Expression left;
    private final Expression right;

    public AndExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean interpret(Context context) {
        return left.interpret(context) && right.interpret(context);
    }
}

public class OrExpression implements Expression {
    private final Expression left;
    private final Expression right;

    public OrExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean interpret(Context context) {
        return left.interpret(context) || right.interpret(context);
    }
}

public class NotExpression implements Expression {
    private final Expression expression;

    public NotExpression(Expression expression) {
        this.expression = expression;
    }

    @Override
    public boolean interpret(Context context) {
        return !expression.interpret(context);
    }
}

利用側のコード:構文木を組み立てて評価する

public class Main {
    public static void main(String[] args) {
        Context context = new Context();
        context.setVariable("A", true);
        context.setVariable("B", false);
        context.setVariable("C", true);

        // 「A AND (B OR C)」という論理式を、構文木として組み立てる
        Expression expression = new AndExpression(
            new VariableExpression("A"),
            new OrExpression(
                new VariableExpression("B"),
                new VariableExpression("C")
            )
        );

        boolean result = expression.interpret(context);
        System.out.println("A AND (B OR C) = " + result);

        // 「NOT B AND A」を評価する例
        Expression expression2 = new AndExpression(
            new NotExpression(new VariableExpression("B")),
            new VariableExpression("A")
        );
        System.out.println("NOT B AND A = " + expression2.interpret(context));
    }
}

実行結果:

A AND (B OR C) = true
NOT B AND A = true

image.png

AndExpression・OrExpression・NotExpression・VariableExpressionという4種類のクラスの組み合わせだけで、任意の複雑さの論理式を表現できます。

「A AND (B OR C)」という式は、AndExpressionの中にOrExpressionが入れ子になった、木構造(構文木)として表現されており、interpret()を呼ぶと、この木構造を再帰的に辿りながら評価されます。

新しい演算子(例えばXOR)を追加したい場合も、新しいExpression実装クラスを1つ追加するだけで対応できます。

Compositeパターンとの関係

Interpreterパターンの構文木の構造は、以前解説したCompositeパターンとよく似ています。

実際、AndExpressionやOrExpressionは、複数の子Expressionを持つという点で、Compositeパターンにおける「Composite(枝)」の役割を、VariableExpressionは「Leaf(葉)」の役割を果たしていると捉えることもできます。

使用場面

  • 簡易的な設定ファイル・クエリ言語・ルールエンジン(条件式の評価など)を自作したい場合
  • SQL文やロジック式のような、限定的な文法を持つ言語の解釈処理
  • 正規表現エンジン、数式パーサーなど、構文解析が必要な処理

注意点

Interpreterパターンは、文法規則が複雑になるほどクラス数が増え、パフォーマンスも低下しやすい傾向があります。

実務で本格的な言語処理系が必要な場合は、このパターンを自前で実装するのではなく、ANTLRのような専用のパーサジェネレータや、既存の式評価ライブラリを使うことが一般的です。

GoFの23パターンの中では、実務での直接的な使用頻度が比較的低いパターンとされています。

まとめ

項目 内容
解決する課題 特定の文法規則に従った文を、コードとして解釈・評価したい
実現方法 文法の各要素をクラスとして表現し、組み合わせた構文木として文を表現する
メリット 新しい文法要素の追加が、新しいクラスの追加だけで対応できる
注意点 複雑な文法には不向き。実務では専用のパーサジェネレータが使われることが多い

おすすめ書籍

GoFの23パターンをより深く学びたい方には、以下の書籍がおすすめです。
Java言語のサンプルコードとUMLを使い、初心者にもわかりやすく解説されています。

Java言語で学ぶデザインパターン入門 第3版 [ 結城 浩 ]

※本リンクはアフィリエイトリンクを含みます。

参考

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?