
Interpreter(インタプリタ)は、「文法をコードとして表現し、独自のミニ言語を解釈・実行する」 デザインパターンです。
たとえば「数式」「条件式」「ドメイン固有言語(DSL)」などをプログラムで解釈する仕組みを作るときに使えます。
1つの文法規則(構文)で、1つのクラスとして表現するのが基本です。
独自の“文法”を作り、それを自動で読み解く仕組み(インタプリタ)を構築することを目的とします。
構成要素
| 役割 |
説明 |
| AbstractExpression(抽象式) |
式の共通インターフェース(interpret()メソッド) |
| TerminalExpression(終端式) |
値や変数など、文法の最小単位を表す式 |
| NonTerminalExpression(非終端式) |
文法規則(AND、OR、ADDなど)を表す式 |
| Context(文脈 |
変数や環境情報を保持するクラス |
サンプルコード
簡単な「AND」「OR」式のインタプリタ
Context(文脈情報)
class Context {
constructor(data) {
this.data = data; // 例:{ admin: true, editor: false }
}
get(name) {
return this.data[name];
}
}
AbstractExpression(抽象式)
class Expression {
interpret(context) {
throw new Error("interpret() must be implemented");
}
}
TerminalExpression(終端式:変数や値)
class VariableExpression extends Expression {
constructor(name) {
super();
this.name = name;
}
interpret(context) {
return context.get(this.name);
}
}
NonTerminalExpression(非終端式:AND / OR)
class AndExpression extends Expression {
constructor(expr1, expr2) {
super();
this.expr1 = expr1;
this.expr2 = expr2;
}
interpret(context) {
return this.expr1.interpret(context) && this.expr2.interpret(context);
}
}
class OrExpression extends Expression {
constructor(expr1, expr2) {
super();
this.expr1 = expr1;
this.expr2 = expr2;
}
interpret(context) {
return this.expr1.interpret(context) || this.expr2.interpret(context);
}
}
実行例(Client)
const context = new Context({ admin: true, editor: false });
// 式:admin AND editor
const rule1 = new AndExpression(
new VariableExpression("admin"),
new VariableExpression("editor")
);
// 式:admin OR editor
const rule2 = new OrExpression(
new VariableExpression("admin"),
new VariableExpression("editor")
);
console.log(rule1.interpret(context)); // false
console.log(rule2.interpret(context)); // true
ポイント解説
最初にContextクラスで、単語を複数セットして、"AndExpression"と"OrExpression"で、それぞれ、ANDとORの判定を実行するパターンです。
コードが長くてめんどくさく感じるかもしれませんが、実際に使う場合は、もっと複雑な個別のシステム内でのみ使用する計算式(判定分)になるハズです。
サンプルのような書き方以外にも、独自構文に応じた処理をクラス分解して、共通化することで、便利に使えるようになります。
また汎用性を増すための、構造整理も必要になりますが、複数のデザインパターンを組み合わせることで、安定したシステムになるでしょう。
メリット
・独自のルールやDSL(ドメイン固有言語)を実装できる
・構文木をオブジェクトとして扱える(再利用・拡張が容易)
・条件式やルール設定などを柔軟に表現できる
デメリット
・クラスやオブジェクトが増えやすい
・文法が複雑になると処理構造も複雑化
・大規模パーサや言語実装には**他の仕組み(パーサジェネレータ等)**が向いている
あとがき
インタプリタのデザインパターンがよく使われる場面として、数式計算、条件式、ルールエンジン、DSL構築などがあります。
1つの計算式で、サンプルコードのように、複数のクラス構成が必要になるので、クラスのグループを一塊にしたフォルダ構成や、命名規則などで上位管理する必要があります。
そもそも、PHPやJavascriptもプログラム言語としてのインタプリタという領域を考えると、独自システムのカスタマイズ要素として汎用的に使えるようにすると、利用幅の大きなシステムに繋がるかもですね。
0 件のコメント:
コメントを投稿