ちゃんなるぶろぐ

エンジニア5年生🧑‍💻 オライリーとにらめっこする毎日。

【10分でわかる🇯🇵🇺🇸🎙️】TypeScriptでDesign Pattern〜Interpreter Pattern〜

どうも、ちゃんなるです!

今回は、Interpreter Patternを紹介します🖐️

概要

Interpreter Patternは、特定の文法や言語を解釈・評価するアルゴリズムを表現する際に役立ちます。

簡潔なコードで柔軟性と拡張性が向上し、言語の規則を変更しやすくなるのがInterpreter Patternの大きな利点です。

今回示すプログラムの設計

具体的なシナリオとして、電卓アプリケーションを考えます。

ユーザーが入力した数式を解釈し、計算結果を返すプログラムを設計します。

クラス図

サンプルコードのクラス図:Mermaid Live Editorで作成

クラス名 役割
Expression 抽象式クラス。すべての式クラスの基底となる。
TerminalExpression 数値リテラルを表すクラス。
NonTerminalExpression 二項演算を表すクラス。
Context 解釈のための情報を提供するクラス。
CalculatorContext 電卓アプリケーションの文脈を表すクラス。

サンプルコード

abstract class Expression {
    abstract interpret(context: Context): number;
}
class TerminalExpression extends Expression {
    private value: number;

    constructor(value: number) {
        super();
        this.value = value;
    }

    interpret(context: Context): number {
        // 必要に応じてcontextの値を使う
        return this.value;
    }
}
class NonTerminalExpression extends Expression {
    private left: Expression;
    private right: Expression;
    private operation: string;

    constructor(left: Expression, right: Expression, operation: string) {
        super();
        this.left = left;
        this.right = right;
        this.operation = operation;
    }

    interpret(context: Context): number {
        switch (this.operation) {
            case '+':
                return this.left.interpret(context) + this.right.interpret(context);
            case '-':
                return this.left.interpret(context) - this.right.interpret(context);
            case '*':
                return this.left.interpret(context) * this.right.interpret(context);
            case '/':
                return this.left.interpret(context) / this.right.interpret(context);
            default:
                throw new Error('Invalid operation');
        }
    }
}

Interpreter Patternの特徴として、処理の文脈(Context)を扱うことが挙げられます。

今回の例は単純な四則演算なので特に必要ないのですが、Context内に具体的なより複雑な処理を持たせることで、より柔軟な設計が可能になります🖐️

abstract class Context {}
class CalculatorContext extends Context {}

実際に使ってみましょう🖐️

以下のような式を解釈するプログラムを実装します。

(5 + 4) * 3 / 2
const context = new CalculatorContext();
const expression = new NonTerminalExpression(
    new NonTerminalExpression(new TerminalExpression(5), new TerminalExpression(4), '+'),
    new TerminalExpression(3),
    '*'
);
const result = expression.interpret(context) / 2;
console.log(result); // 13.5

上記のように、解釈する式を作り、interpretメソッドを呼び出すことで計算できます🖐️

また、CalculatorContextクラスを継承したクラスを作成することで、変数などの文脈情報を追加することもできます👍

Interpreter Patternの使い道

組み合わせられるデザインパターン

  • Composite Pattern: 複雑な文法構造を木構造で表現する際に適用できます。

chan-naru.hatenablog.com

  • Visitor Pattern: インタプリタの動作を変更したい場合に、Visitorパターンと組み合わせることで柔軟性を向上させることができます。

chan-naru.hatenablog.com

  • Flyweight Pattern: 大量のインスタンスを効率的に扱うことができるパターンで、頻繁に使われるオブジェクトを再利用することでメモリ使用量を削減できます。インタプリタにおいて、共通するオブジェクトが多数存在する場合に適用できます。

chan-naru.hatenablog.com

まとめ

Interpreter Patternは特定の文法や言語を解釈・評価する際に役立ち、簡潔なコードで柔軟性と拡張性が向上します。

電卓アプリケーションの例を通じて、TypeScriptでの実装方法とクラス図を、加えて適用される典型的なシナリオと、他のデザインパターンとの組み合わせも紹介しました👍

ぜひ参考にして、効率的で拡張性の高いプログラムを設計してみてくださいね🔥

参考文献

www.oreilly.com

en.wikipedia.org