23.Interpreter パターン
- 2012/04/26 一部修正しました
- 23.1 Interpreterパターンとは
- 23.2 サンプルケース
- 23.3 Interpreterパターンまとめ
23.1 Interpreter パターンとは
第23章では Interpreter パターンを学びます。Interpreter とは、英語で「解釈者・説明者」を意味する単語です。 何らかのフォーマットで書かれたファイルの中身を、解析した結果に則って何らかの処理を行いたい場合があります。 Interpreter パターンとは、このような「解析した結果」得られた手順に則った処理を実現するために最適なパターンです。
1 + 2 × ( 4 + 2 )という計算式を処理する場合を考えて見ましょう。まずは、処理を解析すると、以下のような構文木が得られます。
このような構文木に則った処理を実現するには、Interpreter パターンが利用できます。
23.2 サンプルケース
サンプルケースでは、「あきちゃんラーメンの作り方」を考えて見ましょう。
あきちゃんラーメンは、今日本でもっとも売れている即席めんです。この即席めんの作り方は、
- カップめんに「粉末スープ」を入れる
- お湯を注ぐ
- 3分待つ
- 液体スープを入れる
このようにとっても簡単にできてしまいます。これを構文木にして見みたのが以下の図です。
この構文木から「処理」と「処理対象」を抜き出してみましょう。
「処理」に分類されるものは、「足す」「3分待つ」の2つです。一方「処理対象」に分類されるものは、 「粉末スープ」「麺」「お湯」「液体スープ」だけでなく「粉末スープと麺を足したもの」 「粉末スープと麺を足したものにお湯を足したもの」「粉末スープと麺を足したものにお湯を足したものを3分置いたもの」 なども、処理対象と考えられます。
このように、「処理対象」には「処理結果」も含まれるため、この2つを同一視するために、 Interpreter パターンは Composit パターンと同じ構造をとります。
まずは、ソースコードを見てみましょう。/** * 処理対象を表すインタフェース */ public interface Operand { /** * 処理対象を表す文字列を返すメソッドです。 * @return operandString */ public String getOperandString(); }「処理対象」「処理結果」を表すクラスは、このインタフェースを実装します。
/** * 処理対象を表すクラス */ public class Ingredient implements Operand { /** * この処理対象を表す文字列 */ private String operandString = null; /** * 処理対象を表す文字列を引数に取るコンストラクタ * @param operandString */ public Ingredient(String operandString) { this.operandString = operandString; } /** * 処理対象を表す文字列を返すメソッド * @return operandString */ public String getOperandString() { return this.operandString; } }/** * 処理結果を表すクラス */ public class Expression implements Operand { /** * operator */ private Operator operator = null; /** * 処理内容を表す operator を引数に取るコンストラクタ * @param operator */ public Expression(Operator operator) { this.operator = operator; } /** * 処理の結果得られる Operand の文字列表現を返すメソッド * @return operandString */ public String getOperandString() { return operator.execute().getOperandString(); } }処理を表すインタフェースは、以下のようになります。
/** * 処理を表すインタフェース */ public interface Operator { /** * 実行結果の operand を返すメソッド * @return operand */ public Operand execute(); }/** * 足し合わせる処理を表すクラス */ public class Plus implements Operator { private Operand operand1 = null; private Operand operand2 = null; /** * 足される2つの operand を引数に取るコンストラクタ * @param operand1 * @param operand2 */ public Plus(Operand operand1, Operand operand2) { this.operand1 = operand1; this.operand2 = operand2; } /** * 処理を実行するメソッド * @return string */ public Operand execute() { return new Ingredient(operand1.getOperandString() + "と" + operand2.getOperandString() + "を足したもの"); } }/** * 「待つ」という処理を表すクラス */ public class Wait implements Operator { private int minutes = -1; private Operand operand = null; /** * 足される2つの operand を引数に取るコンストラクタ * @param minutes * @param operand */ public Wait(int minutes, Operand operand) { this.minutes = minutes; this.operand = operand; } /** * 処理を実行するメソッド * @return string */ public Operand execute() { return new Ingredient(operand.getOperandString() + "を" + minutes + "分置いたもの"); } }以上をクラス図で表すと以下のようになります。
Interpreter パターンでは、ひとつの文法規則をひとつのクラスで表現します。
サンプルケースでは、「足す」「待つ」といった処理をひとつのクラスで表現しており、 構文の解析結果に合わせて、処理を実行していくことを可能にしています。
23.3 Interpreter パターンまとめ
Interpreter パターンの一般的なクラス図は、以下のようになります。
[引用] 『Java言語で学ぶ デザインパターン入門』(結城浩 ソフトバンクパブリッシング株式会社出版 2001年)