🐷
デザインパターンを学ぶ #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