Skip to main content

🧩 Interpreter Pattern

✅ Intent

  • Represent conditional logic or business rules as a grammar, and define a structure for interpreting and evaluating it
  • Ideal for building domain-specific languages (DSLs) for rule evaluation

✅ Motivation

  • Complex and frequently changing conditional logic can be defined as an abstract syntax tree and delegated to an interpreter
  • Transforms deeply nested if/switch statements into a flexible, extensible structure

✅ When to Use

  • Business rule engines, filter conditions, search expressions, etc.
  • When rules are defined by non-engineers or via configuration files and evaluated at runtime

✅ Code Example

// 文法インターフェース
interface Expression {
interpret(userType: string, basePrice: number): number;
}

// ターミナル式(具体的な条件と計算)
class DiscountExpression implements Expression {
constructor(private targetType: string, private rate: number) {}

interpret(userType: string, basePrice: number): number {
return userType === this.targetType ? basePrice * this.rate : basePrice;
}
}

// 非終端式(ANDやORなどにも拡張可能)
class DiscountInterpreter {
private expressions: DiscountExpression[] = [];

add(expression: DiscountExpression) {
this.expressions.push(expression);
}

interpret(userType: string, basePrice: number): number {
for (const expr of this.expressions) {
const result = expr.interpret(userType, basePrice);
if (result !== basePrice) return result;
}
return basePrice;
}
}

// 利用例
const interpreter = new DiscountInterpreter();
interpreter.add(new DiscountExpression("student", 0.8));
interpreter.add(new DiscountExpression("member", 0.9));
interpreter.add(new DiscountExpression("vip", 0.7));

console.log(interpreter.interpret("vip", 1000)); // 700
console.log(interpreter.interpret("student", 1000)); // 800
console.log(interpreter.interpret("guest", 1000)); // 1000

✅ Explanation

This code applies the Interpreter pattern to represent discount rules as a grammar and evaluate them flexibly.
The Interpreter pattern defines a grammar for a given language and provides an interpreter to evaluate expressions written in that language. It is particularly useful for complex or dynamic rule evaluation.

1. Overview of the Interpreter Pattern

  • Expression: Defines the common interface for all grammar expressions

    • Represented by Expression in this code
  • TerminalExpression: Implements atomic expressions containing specific logic

    • Represented by DiscountExpression
  • NonTerminalExpression: Combines multiple expressions and defines how they are evaluated

    • Represented by DiscountInterpreter
  • Client: Constructs the grammar and executes the interpretation

    • In this code, the part where multiple DiscountExpressions are added to DiscountInterpreter and interpret is called

2. Key Classes and Their Roles

  • Expression

    • Common interface for all expressions
    • Declares the method interpret(userType: string, basePrice: number): number
  • DiscountExpression

    • A TerminalExpression
    • Applies a specific discount rate (rate) if the user type matches (targetType)
  • DiscountInterpreter

    • A NonTerminalExpression
    • Holds multiple DiscountExpression instances and evaluates them in order
    • Returns the result of the first matching expression
  • Client Code

    • Adds multiple DiscountExpressions to DiscountInterpreter and executes the evaluation using interpret

3. UML Class Diagram

4. Benefits of the Interpreter Pattern

  • Flexible Rule Definition: Rules can be expressed as objects, enabling concise representation of complex conditions
  • Extensibility: New rules can be added simply by creating a new DiscountExpression and adding it to the interpreter
  • Reusability: Each expression is independent and can be reused across different contexts

This design is highly effective for managing complex or dynamic rule sets, and is especially useful in scenarios where rules may evolve or grow over time.