Interpreterパターンとは|GoFデザインパターンの解説

デザインパターンとは IT技術
IT技術

このページでは、GoF(Gang of Four)が提唱した23のデザインパターンの一つである「Interpreterパターン」について解説します。

Interpreterパターンは、文法規則に基づいて文を解釈するためのパターンであり、式や文の評価を自動化する場面でよく使用されます。

具体的な使用方法やJavaでの実装例も含め、詳細に説明しますので、ぜひ参考にしてください

Interpreterパターンとは

ここでは、Interpreterパターンの概要と、その役割について説明します。

Interpreterパターンは、言語の文法を解析し、構文ツリーに基づいて文や式を評価するためのパターンです。

プログラミング言語の文法規則や、テキスト解析、SQLクエリの解釈などで使用されることが多いパターンです。

このパターンでは、与えられた文法に従った「文」を解釈し、それを適切なアクションに変換することが目的です。

特定のドメイン言語(DSL: Domain-Specific Language)を解釈する必要がある場合に有効な手法です。

Interpreterパターンのメリットとデメリット

Interpreterパターンを使用することで、文法を定義しやすくなり、解析や評価が明確になります。

しかし、複雑な文法や大規模な文を処理する際には、設計が煩雑になることがあります。

Interpreterパターンの使い方

ここでは、実際にInterpreterパターンをどのように活用するかについて解説します。

Interpreterパターンは、文法規則をクラス階層で表現し、個々のルールを組み合わせて文を解釈します。

たとえば、数式や条件式を評価するために使用される場合が多く、各文法のルールに対応するクラスを作成し、それらを組み合わせて複雑な式を解釈します。

この手法により、文法の追加や変更がしやすくなり、柔軟に対応できるようになります。

適用例

Interpreterパターンは、主に以下のような場面で活用されます。

Interpreterパターンの活用例
  • プログラミング言語の文法解析
  • SQLクエリや正規表現の解析
  • コンパイラやインタプリタの構築

Interpreterパターン実装サンプル

次に、Javaでの簡単なInterpreterパターンの実装例を紹介します。

この例では、簡単な四則演算を解釈するためのインタプリタを作成します

// 抽象的な式を表すインターフェース
interface Expression {
    int interpret();
}

// 数値を表すクラス
class Number implements Expression {
    private int number;

    public Number(int number) {
        this.number = number;
    }

    @Override
    public int interpret() {
        return this.number;
    }
}

// 足し算を表すクラス
class Add implements Expression {
    private Expression leftExpression;
    private Expression rightExpression;

    public Add(Expression left, Expression right) {
        this.leftExpression = left;
        this.rightExpression = right;
    }

    @Override
    public int interpret() {
        return leftExpression.interpret() + rightExpression.interpret();
    }
}

// 引き算を表すクラス
class Subtract implements Expression {
    private Expression leftExpression;
    private Expression rightExpression;

    public Subtract(Expression left, Expression right) {
        this.leftExpression = left;
        this.rightExpression = right;
    }

    @Override
    public int interpret() {
        return leftExpression.interpret() - rightExpression.interpret();
    }
}

// クライアントコード
public class InterpreterPatternExample {
    public static void main(String[] args) {
        // "5 + 3 - 2" を解釈する
        Expression expression = new Subtract(
            new Add(new Number(5), new Number(3)),
            new Number(2)
        );

        System.out.println("結果: " + expression.interpret());  // 結果: 6
    }
}

この実装では、Numberクラスが数値を表し、Addクラスが足し算を、Subtractクラスが引き算を表しています。

クライアントコードでは、5 + 3 - 2という式を解釈し、結果を計算しています

C++での実装例

次に、C++での簡単なInterpreterパターンの実装例を紹介します。

#include <iostream>
#include <memory>

// 抽象的な式を表すインターフェース
class Expression {
public:
    virtual int interpret() = 0;
    virtual ~Expression() = default;
};

// 数値を表すクラス
class Number : public Expression {
private:
    int number;

public:
    Number(int number) : number(number) {}

    int interpret() override {
        return number;
    }
};

// 足し算を表すクラス
class Add : public Expression {
private:
    std::unique_ptr<Expression> leftExpression;
    std::unique_ptr<Expression> rightExpression;

public:
    Add(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right)
        : leftExpression(std::move(left)), rightExpression(std::move(right)) {}

    int interpret() override {
        return leftExpression->interpret() + rightExpression->interpret();
    }
};

// 引き算を表すクラス
class Subtract : public Expression {
private:
    std::unique_ptr<Expression> leftExpression;
    std::unique_ptr<Expression> rightExpression;

public:
    Subtract(std::unique_ptr<Expression> left, std::unique_ptr<Expression> right)
        : leftExpression(std::move(left)), rightExpression(std::move(right)) {}

    int interpret() override {
        return leftExpression->interpret() - rightExpression->interpret();
    }
};

// クライアントコード
int main() {
    // "5 + 3 - 2" を解釈する
    std::unique_ptr<Expression> expression = std::make_unique<Subtract>(
        std::make_unique<Add>(std::make_unique<Number>(5), std::make_unique<Number>(3)),
        std::make_unique<Number>(2)
    );

    std::cout << "結果: " << expression->interpret() << std::endl; // 結果: 6

    return 0;
}

C#での実装例

次に、C#での簡単なInterpreterパターンの実装例を紹介します。

using System;

// 抽象的な式を表すインターフェース
public interface Expression
{
    int Interpret();
}

// 数値を表すクラス
public class Number : Expression
{
    private int _number;

    public Number(int number)
    {
        _number = number;
    }

    public int Interpret()
    {
        return _number;
    }
}

// 足し算を表すクラス
public class Add : Expression
{
    private Expression _leftExpression;
    private Expression _rightExpression;

    public Add(Expression left, Expression right)
    {
        _leftExpression = left;
        _rightExpression = right;
    }

    public int Interpret()
    {
        return _leftExpression.Interpret() + _rightExpression.Interpret();
    }
}

// 引き算を表すクラス
public class Subtract : Expression
{
    private Expression _leftExpression;
    private Expression _rightExpression;

    public Subtract(Expression left, Expression right)
    {
        _leftExpression = left;
        _rightExpression = right;
    }

    public int Interpret()
    {
        return _leftExpression.Interpret() - _rightExpression.Interpret();
    }
}

// クライアントコード
public class InterpreterPatternExample
{
    public static void Main(string[] args)
    {
        // "5 + 3 - 2" を解釈する
        Expression expression = new Subtract(
            new Add(new Number(5), new Number(3)),
            new Number(2)
        );

        Console.WriteLine("結果: " + expression.Interpret());  // 結果: 6
    }
}

まとめ

この記事では、GoFデザインパターンの一つであるInterpreterパターンについて解説しました。

Interpreterパターンは、特定の文法規則に基づいて文や式を解釈するためのパターンであり、複雑な解析を簡素化するために使用されます。

また、Java、C++、C#による実装例を示し、どのようにこのパターンを活用できるかについても説明しました。

他のプログラミング言語でもこのパターンを応用できるため、様々なシステムに適用可能です。

これを機に、Interpreterパターンの理解を深め、実際の開発に役立ててください。

タイトルとURLをコピーしました