🐷

デザインパターンを学ぶ #20 インタープリタ(Interpreter)

に公開

1. はじめに

インタープリタは、独自の小さな言語や式をオブジェクトとして表現し、評価(解釈)するためのパターン。検索フィルタや条件式など「簡単な文法」を安全に実装したいときに使う。

2. Interpreterとは?

文法要素をクラス化し、式の木(構文木)を組み立て、共通メソッド interpret() で評価する。if/switchを直書きするより拡張に強い。

登場役

  • AbstractExpression … 共通インターフェース(interpret(context)
  • TerminalExpression … 終端(定数・変数)
  • NonterminalExpression … 終端以外(演算子、AND/OR、加算など)
  • Context … 変数や環境を保持

3. 実装イメージ(PHP)

<?php
interface Expr { public function interpret(array $ctx): int|bool; }

// 終端: 数値
class NumberExpr implements Expr {
    public function __construct(private int $value) {}
    public function interpret(array $ctx): int { return $this->value; }
}

// 終端: 変数
class VarExpr implements Expr {
    public function __construct(private string $name) {}
    public function interpret(array $ctx): int { return $ctx[$this->name] ?? 0; }
}

// 非終端: 加算
class AddExpr implements Expr {
    public function __construct(private Expr $l, private Expr $r) {}
    public function interpret(array $ctx): int {
        return $this->l->interpret($ctx) + $this->r->interpret($ctx);
    }
}

// 非終端: 大なり比較
class GreaterExpr implements Expr {
    public function __construct(private Expr $l, private Expr $r) {}
    public function interpret(array $ctx): bool {
        return $this->l->interpret($ctx) > $this->r->interpret($ctx);
    }
}

// (x + 10) > y
$expr = new GreaterExpr(new AddExpr(new VarExpr('x'), new NumberExpr(10)), new VarExpr('y'));

var_dump($expr->interpret(['x'=>5,'y'=>20]));   // false
var_dump($expr->interpret(['x'=>15,'y'=>20]));  // true

4. メリット・デメリット

メリット

  • 文法をクラス単位に分割でき、拡張しやすい
  • 小さなDSLの安全な埋め込みに向く

デメリット

  • 文法が増えるとクラス数が増大しやすい
  • 本格的な言語処理はパーサジェネレータ等の方が適切

5. 使いどころ

  • 検索条件やフィルタDSL(例: price > 1000 AND stock > 0
  • 設定ファイルの式評価
  • 業務ロジックの簡易スクリプト

小さな文法ならインタープリタで十分。複雑化の兆しが出たら言語処理系の導入を検討する。

Discussion