デザインパターン勉強会 第14回：ChainOfResponsibilityパターン 

<!-- デザインパターン勉強会 第14回：ChainOfResponsibilityパターン -->
# はじめに  
本エントリーは某社内で実施するデザインパターン勉強会向けの資料となります。 
本エントリーで書籍「[Java言語で学ぶデザインパターン入門](http://www.hyuki.com/dp/)」をベースに学習を進めますが、サンプルコードはC#に置き換えて解説します。  
  
第1回：[Iteratorパターン](http://qiita.com/Nuits/items/800f080d44b52e1cae18)  
第2回：[Adapterパターン](http://qiita.com/Nanakusajp/items/747d1913b1e8bea8d340)  
第3回：[Template Methodパターン](http://qiita.com/_kyam/items/9b5722e6a9635af6e18b)  
第4回：[Factory Methodパターン](https://qiita.com/ayayo/items/3eece04bbc4b7504179a)  
第5回：[Singletonパターン](https://qiita.com/Keenag/items/cae53d55cb953562fee4)  
第6回：[Prototypeパターン](https://qiita.com/aconit96/items/9235d30a07f508886c7e)  
第7回：[Builderパターン](https://qiita.com/Uesk/items/8f12be304671e9905795)  
第8回：[Abstract Factoryパターン](https://qiita.com/buru/items/bb3930dda1bdd2b5f70b)  
第9回：[Bridgeパターン](https://qiita.com/mitakaosamu/items/cff9a39953ae03092f43)  
第10回：[Strategyパターン](https://qiita.com/a1146234/items/fdecc374b7225d99ab07)  
第11回：[Compositeパターン](https://qiita.com/Nanakusajp/items/32ed648eaadaa9910159)  
第12回：[Decoratorパターン](https://qiita.com/_kyam/items/3072a70c1f31f690e00c#_reference-6ceee69f61eb05add1bd)  
第13回：[Visitorパターン](https://qiita.com/ayayo/items/cf63041d047ea5b676c3#_reference-fd2b59d78f8524c2c305)
  
  
# ChainOfResponsibilityパターンとは  
複数のオブジェクトをチェーン(鎖)のようにつないでおき、要求を処理することが可能なオブジェクトにわたるまで、要求を受け流していくパターンです。


---

# サンプルプログラムのクラス図  
ChainOfResponsibilityパターンを使用したサンプルプログラムを紹介します。  
![ChainOfResponsibility_class.JPG](https://qiita-image-store.s3.amazonaws.com/0/199196/99231fa0-3fda-0af9-860b-2b1fa96afa0d.jpeg)

  
---

# 各クラスの役割  
| クラス名       | 役割          |
|:--------------|:--------------|
| Issue       | 発生した問題を表すクラス。問題管理番号(IssueNumber)を持つ |
| Support      | 問題解決のサポートを行う抽象クラス|
| LimitSupport      | 問題解決のサポートを行う具象クラス（指定した番号未満の問題を解決）|
| OddSupport      | 問題解決のサポートを行う具象クラス（奇数番号の問題を解決）|
| SpecialSupport      | 問題解決のサポートを行う具象クラス(特定の問題を解決)|
| Program     | Supportたちの連鎖を作り、問題を発生させる動作テスト用クラス|
  

---

# Issueクラス  
Issueクラスは、発生した問題を表現するクラスです。IssueNumberは問題を管理する番号です。　　
コンストラクタで、IssueNumberを設定します。

```csharp
namespace ChainOfResponsibilitySample
{
    public class Issue
    {
        public int IssueNumber { get; private set; }

        public Issue(int issueNumber)
        {
            IssueNumber = issueNumber;
        }
    }
}
```

---

# Supportクラス  
Supportクラスは、問題を解決する連鎖を作るための抽象クラスです。 
_nextSupportフィールドは、次の問題解決先を差します。 
SetNextSupportメソッドは、次の問題解決先を設定します。 
Resolveメソッドは、サブクラスで実装することを想定した抽象メソッドです。戻り値がtrueのときは要求が処理されたことを表し、falseのときは要求はまだ処理されていない(次のサポート先に問題解決を任せる)ことを表します。 
SupportIssueメソッドは、Resolveメソッドを呼び出し、戻り値がfalseなら、次のサポートに問題解決を任せます。 次のサポートがいない場合は、連鎖の最後となり、サポートできなかった旨を通知するメッセージを出力します。

```csharp
using System;

namespace ChainOfResponsibilitySample
{
    public abstract class Support
    {
        private string _staffName;

        private Support _nextSupport;

        public Support(string staffName)
        {
            _staffName = staffName;
        }

        public Support SetNextSupport(Support nextSupport)
        {
            return _nextSupport = nextSupport;
        }

        public void SupportIssue(Issue issue)
        {
            if (Resolve(issue))
            {
                Console.WriteLine("問題" + issue.IssueNumber + "は" + _staffName + "が解決しました。");
            }
            else if (_nextSupport != null)
            {
                _nextSupport.SupportIssue(issue);
            }
            else
            {
                Console.WriteLine("問題" + issue.IssueNumber + "は現在のサポート体制では解決できませんでした。");
            }
        }

        protected abstract bool Resolve(Issue issue);

    }
}
```  

---  

# LimitSupportクラス  
LimitSupportクラスは、limitIssueNumberで指定した問題管理番号未満の問題を解決するクラスです。

```csharp
namespace ChainOfResponsibilitySample
{
    public class LimitSupport : Support
    {

        private int _limitIssueNumber;

        public LimitSupport(string staffName, int limitIssueNumber) : base(staffName)
        {

            _limitIssueNumber = limitIssueNumber;
        }

        protected override bool Resolve(Issue issue)
        {
            return issue.IssueNumber < _limitIssueNumber;
        }
    }
}
```  

---  

# OddSupportクラス  
OddSupportクラスは、問題管理番号が奇数の問題を解決するクラスです。

```csharp
namespace ChainOfResponsibilitySample
{
    public class OddSupport : Support
    {
        public OddSupport(string staffName) : base(staffName)
        {
        }

        protected override bool Resolve(Issue issue)
        {
            return issue.IssueNumber % 2 == 1;
        }
    }
}
```  

---  

# SpecialSupportクラス  
SpecialSupportクラスは、指定した問題管理番号のみ問題を解決するクラスです。

```csharp
namespace ChainOfResponsibilitySample
{
    public class SpecialSupport : Support
    {
        private int _specialNumber;

        public SpecialSupport(string staffName, int specialNumber) : base(staffName)
        {
            _specialNumber = specialNumber;
        }

        protected override bool Resolve(Issue issue)
        {
            return issue.IssueNumber == _specialNumber;
        }
    }
}
```  

---

# Programクラス  
動作確認クラスでは、まず各サポートのインスタンスを作成しています。次にSetNextSupportメソッドを使用して、サポートの順番を設定しています。 
そして、6件の問題を発生させ、LimitSupportであるNagatomoさんに1次処理をお願いしています。

```csharp
using System;

namespace ChainOfResponsibilitySample
{
    public class Program
    {
        public static void Main(string[] args)
        {
            Support limitSupport = new LimitSupport("Nagatomo", 3);
            Support oddSupport = new OddSupport("Kagawa");
            Support SpecialSupport = new SpecialSupport("Honda", 4);

            limitSupport.SetNextSupport(oddSupport).SetNextSupport(SpecialSupport);

            var IssueCount = 6;
            //　6件の問題が発生
            for (int i = 1; i <= IssueCount; i++)
            {
                limitSupport.SupportIssue(new Issue(i));
            }

            Console.ReadKey();
        }
    }
}

```  

---

# 実行結果 
実行結果は以下のようになります。  

```
問題1はNagatomoが解決しました。
問題2はNagatomoが解決しました。
問題3はKagawaが解決しました。
問題4はHondaが解決しました。
問題5はKagawaが解決しました。
問題6は現在のサポート体制では解決できませんでした。
```  

問題1,2は3未満のため、LimitSupportで、Nagatomoが解決できます。 
問題3はNagatomoでは解決できないため、解決処理の責任がKagawaに移ります。OddSupportのKagawaは、問題3は解決できますが偶数である問題4は解決できません。
したがって、問題4の解決処理の責任はHondaに移ります。SpecialSupportのHondaは問題4のみ解決することができます。 
問題5は3以上且つ奇数のため、Nagatomo→Kagawaと責任が受け流され、Kagawaが解決します。 
問題6は、全てのサポートで解決が不可能であるため、サポートできない旨のメッセージが表示されています。

---

# ChainOfResponsibilityパターン使用によるメリット

- 利用者側は、内部構造を意識することなく、連鎖関係のある任意のオブジェクトに要求をすることで、適切な処理者によって要求が処理される
- 処理者側は、自分ができる処理のみ対応すれば良いので、簡潔に処理が記述できる

---

# ChainOfResponsibilityパターンを使わないほうが良い場合
　利用者と処理者の関係が固定的で、処理速度が重要な場合は使用しないほうが良い

---

# 振り返り
ChainOfResponsibilityパターンとは
複数のオブジェクトをチェーン(鎖)のようにつないでおき、要求を処理することが可能なオブジェクトにわたるまで、要求を受け流していくパターンです。

---

# サンプルコード  
以下に公開しています。  
https://github.com/Keenag/DesignPatternStudyGroup/tree/master/ChainOfResponsibilitySample

---