デザインパターン勉強会　第二十三回：Interpreterパターン

# はじめに  

本エントリーは某社内で実施するデザインパターン勉強会向けの資料となります。
本エントリーで書籍「[Java言語で学ぶデザインパターン入門](http://www.hyuki.com/dp/)」をベースに学習を進めますが、サンプルコードはC#に置き換えて解説します。
なお過去分はこちら

第一回：[Iteratorパターン](https://qiita.com/Nuits/items/800f080d44b52e1cae18)
第二回：[Adapterパターン](http://qiita.com/Nanakusajp/items/747d1913b1e8bea8d340)
第三回：[Template Methodパターン](http://qiita.com/_kyam/items/9b5722e6a9635af6e18b#_reference-67658aa746587e3a56f0)
第四回：[Factory Methodパターン](https://qiita.com/ayayo/items/3eece04bbc4b7504179a)
第五回：[Singletonパターン](https://qiita.com/Keenag/items/cae53d55cb953562fee4)
第六回：[Prototypeパターン](https://qiita.com/aconit96/items/9235d30a07f508886c7e)
第七回：[Builderパターン](https://qiita.com/Uesk/items/8f12be304671e9905795)
第八回：[Abstract Factoryパターン](https://qiita.com/buru/items/bb3930dda1bdd2b5f70b)
第九回：[Bridgeパターン](https://qiita.com/mitakaosamu/items/cff9a39953ae03092f43)
第十回：[Strategyパターン](https://qiita.com/a1146234/items/fdecc374b7225d99ab07)
第十一回：[Compositeパターン](https://qiita.com/Nanakusajp/items/32ed648eaadaa9910159)
第十二回：[Decoratorパターン](https://qiita.com/_kyam/items/3072a70c1f31f690e00c)
第十三回：[Visitorパターン](https://qiita.com/ayayo/items/cf63041d047ea5b676c3)
第十四回：[Chain of Responsibilityパターン](https://qiita.com/Keenag/items/6ef9cd9671aca38833d8)
第十五回：[Facadeパターン](https://qiita.com/aconit96/items/60c924dbc69a059e5746#_reference-9d763076e525fb232407)
第十六回：[Mediatorパターン](https://qiita.com/Uesk/items/5c3f2b2efd1cb4bb17ab#_reference-6f6607cd67571b932942)
第十七回：[Observerパターン](https://qiita.com/buru/items/cc5c4cd32953f62c78c5)
第十八回：[Mementoパターン](https://qiita.com/mitakaosamu/items/31d881ae14b28919e910#_reference-d009419cef2d0741bdc1)
第十九回：[Stateパターン](https://qiita.com/a1146234/items/bba88081b0f84d70da1f)
第二十回：[Flyweightパターン](https://qiita.com/dai329/items/dfbe829f02c064ebdaac)
第二十一回：[Proxyパターン](https://qiita.com/24be_yuuki/items/e088c67547b2fddaf5ac)
第二十二回：[Commandパターン](https://qiita.com/skyc_lin/items/0b4bbebd19225eaed054)

---

# Interpreterパターンとは
Interpreterとは、英語で解釈者、説明者、通訳者といった意味を持ちます。
Interpreterパターンは、実装言語とは異なる何らかのフォーマットで記載された命令を解析して、言語の文法をオブジェクトで表現するパターンです。

---

# Interpreterパターンの目的

主に二つの方向性があると考えます。

1. プログラムを外部から動的に制御可能な仕組みの実現  
2. 特定ドメインで問題を高効率で解決するため（SQLなど）

---

# 典型的な設計パターン

典型的なInterpreterパターンの構造は以下の通りです。

![Interpreter パターン.png](https://qiita-image-store.s3.amazonaws.com/0/99262/59aaedd1-e35f-99bc-e161-624e1ce83359.png)

Contextが「実装言語とは異なる何らかのフォーマット」で記載された実態を表します。
それをAbstractExpressionのConcreteクラスであるInterpreterが解析しつつ実行します。
Clientは処理を呼び出し元になります。


---

# 例題

逆ポーランド記法を利用した四則演算などをよく見かけますが、ここではXMLで記載された四則演算を実行する例を紹介しましょう。
なぜXMLか？文字列のパースが楽だからです。今回のパターンの本質は難しいインタープリター言語の実装ではないため、パースはできるだけ楽をします。

次が実際のXMLで書かれた四則演算です。普通に+-書いた方が圧倒的に短いだろうという突っ込みは禁止です。

```xml
<?xml version="1.0"?>
<Addition>
  <Subtraction>
    <Constant Value="3" />
    <Constant Value="1" />
  </Subtraction>
  <Multiplication>
    <Division>
      <Constant Value="6" />
      <Constant Value="2" />
    </Division>
    <Constant Value="5" />
  </Multiplication>
</Addition>
```

四則演算がXMLでツリー上に定義されており、ツリーを下から遡りながら演算します。演算はElementの名称が表します。

|演算|名称|
|:--|:--|
|足し算|Addition|
|引き算|Subtraction|
|掛け算|Multiplication|
|割り算|Division|
|定数|Constant|

つまり上のXMLは次の計算を表します。
(3 - 1) + ((6 / 2) * 5)
17が計算できれば成功です。


# サンプルクラス図  

という訳で、次がそのクラス図になります。

![Interpreter Pattern.png](https://qiita-image-store.s3.amazonaws.com/0/99262/93c0f6cc-9b3c-0ae4-e263-0441538eb169.png)

CalcExpressionがコンポジットパターンになっているのが見て取れます。

---

# 各クラスの役割  

|名前|役割|
|:--|:--|
|Program|インタープリターを利用するクラス|
|Context|XMLで記述された四則演算言語をオブジェクトに解釈するクラス|
|IExpression|なんらかの処理（表現）を表すインターフェース|
|CalcMethod|計算方式を表すEnum|
|CalcExpression|四則演算を表すクラス|
|Constant|定数を表すクラス|

---

# 各種クラスの実装

---

## Program

XMLからContextを読み込み、ContextからIExpressionを生成します。
その後、IExpressionを実行して結果をコンソールへ出力しています。
XMLからオブジェクトへのデシリアライズにはXmlSerializerを利用しています。

```csharp
class Program
{
    static void Main()
    {
        var context = new Context("expressions.xml");
        var expression = context.BuildExpression();
        Console.WriteLine($"expression.Operate() : {expression.Operate()}");
        Console.ReadLine();
    }
}
```
---
## Context

XMLで表現された四則演算言語のオブジェクトに解釈するクラスです。
BuildExpressionメソッドでXMLの構文を解析してIExpressionを構築しています。

```csharp
public class Context
{
    private readonly string _fileName;

    public Context(string fileName)
    {
        _fileName = fileName;
    }

    public IExpression BuildExpression()
    {
        var xmlDocument = new XmlDocument();
        xmlDocument.Load(_fileName);
        return BuildExpression(xmlDocument.DocumentElement);
    }

    public IExpression BuildExpression(XmlElement element)
    {
        if (element.Name == "Constant")
        {
            return new Constant(int.Parse(element.GetAttribute("Value")));
        }
        else
        {
            // 子Elementを再帰的に探索してIExpressionを生成する
            var expressions =
                (from object childNode in element.ChildNodes
                    where childNode is XmlElement
                    select BuildExpression((XmlElement) childNode)).ToList();
            return
                new CalcExpression(
                    (CalcMethod)Enum.Parse(typeof(CalcMethod), element.Name, true),
                    expressions);
        }
    }
}
```

---
## CalcMethod

計算方法を表すメソッドです。

```csharp
public enum CalcMethod
{
    Addition,
    Subtraction,
    Multiplication,
    Division
}
```

---

## CalcExpression

四則演算を実施するクラスです。
引数で渡されたCalcMethodに従って計算を実施します。

```csharp
public class CalcExpression : IExpression
{
    private readonly Func<int, int, int> _calc;
    private readonly IList<IExpression> _expressions;

    public CalcExpression(CalcMethod calcMethod, IList<IExpression> expressions)
    {
        _expressions = expressions;
        switch (calcMethod)
        {
            case CalcMethod.Addition:
                _calc = (x, y) => x + y;
                break;
            case CalcMethod.Subtraction:
                _calc = (x, y) => x - y;
                break;
            case CalcMethod.Multiplication:
                _calc = (x, y) => x * y;
                break;
            case CalcMethod.Division:
                _calc = (x, y) => x / y;
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(calcMethod), calcMethod, null);
        }
    }

    public int Operate()
    {
        var result = _expressions.First().Operate();
        for (var i = 1; i < _expressions.Count; i++)
        {
            result = _calc(result, _expressions[i].Operate());
        }
        return result;
    }
}
```
## Constant

定数

```csharp
public class Constant : IExpression
{
    private readonly int _value;

    public Constant(int value)
    {
        _value = value;
    }

    public int Operate()
    {
        return _value;
    }
}
```

---

# Interpreterパターンまとめ  

* Interpreterパターンは、実装言語とは異なる何らかのフォーマットで記載された命令を解析して、言語の文法をオブジェクトで表現するパターン
* おもな使用用途に、次のようなケースが考えられる
    * ドメイン専用の言語を作成し、物事を高効率で解決する（SQLなど）  
    * 命令を設定ファイルや外部入力から得ることで動的な振る舞いを実現する 

---
# サンプルコード

以下に公開しています。

[https://github.com/RJ-DesignPattern/DesignPattern/tree/master/InterpreterPattern](https://github.com/RJ-DesignPattern/DesignPattern/tree/master/InterpreterPattern)