Strategy Pattern（Design Pattern）をC#で解説

Design Patternの１つで「**Strategy Pattern**」について解説をします。
この記事は「Head First Design Patterns」を参考に執筆しています。

# Strategy Patternとは
様々な「戦略」を事前に定義しておいて、その「戦略」を場面によって切り替えるデザインパターンです。今回の記事では、「戦略」を「行動」として説明をしていきます。
今回は様々な「アヒル」のゲームを例に、解説・実装をします。

### Baseアヒル
Baseアヒルクラス(Duck)には「鳴く(quack)」、「泳ぐ(swim)」、「display(アヒルを表示する)」、「fly(飛ぶ※飛ばないけど)」の４つの行動が定義されています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/5489124e-bc12-ec7d-3c7a-2f583c03471d.png" width="300" />
Baseアヒルを継承して、他の種類のアヒルクラスも作成することができます。
マガモクラス(MallardDuck)とゴム製アヒルのおもちゃクラス(RubberDuck)を作成します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/348648b0-6e48-ec61-cfa7-025776b678cf.png" width="400" />
こんな感じでクラスを継承して新しいクラスを作成するのですが、クラス内でoverrideし実装するのが普通だと思います。しかし、今回はたまたま２種類しかいないだけであって、もしめちゃくちゃ種類が多いとその分すべてのクラスでoverrideし「行動」を実装しないといけません。さらに近いクラスでグループ分けし、そのクラスを作成(もしくはインターフェースを作成する)後継承するやり方もありかと思います。それは普通のアヒルなら...。今回前提条件として、これらのアヒルのゲームとしていますので、アヒルは進化し、「行動」も進化によって変わってくるようなゲームであるとします。その場合、グループ分けしたクラスではあまり恩恵は受けないと思います。そこで、Strategy Patternによってこのoverride地獄を解決していきます。

## 「戦略(行動)」の定義
displayはどのアヒルも共通の行動として、それ以外はアヒルの種類によって行動が変えることができるとします。
### 鳴く(quack)行動
鳴く行動のインターフェースに、それぞれガーガー鳴く「Quack」クラス、キュッキュッ泣く「Squack」クラス、鳴かない「MuteQuack」クラスを実装する。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/96cebfde-f7a5-a5fc-1cf2-3332f14ae1e3.png" width="400" />
```c# 
public interface IQuackBehavior
{
  void quack();
}

public Quack: IQuackBehavior
{
  public void quack()
  {
    Console.WriteLine("ガーガー");
  }  
}

public Squack: IQuackBehavior
{
  public void quack()
  {
    Console.WriteLine("キュッキュッ");
  }
}

public MuteQuack: IQuackBehavior
{
  public void quack()
  {
    Console.WriteLine("(鳴かないよ)");
  }
}
```

### 泳ぐ(swim)行動
泳ぐ行動のインターフェースに、それぞれ泳ぐ「Swim」クラス、泳がない「SwimNoWay」クラスを実装する。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/24c30bba-06a5-ee64-d183-290230c66ae9.png" width="400" />
```c# 
public interface ISwimBehavior
{
  void swim();
}

public Swim: ISwimBehavior
{
  public void swim()
  {
    // 本当はここに泳ぐ動作を実装します
    Console.WriteLine("泳げるぜ");
  }  
}

public SwimNoWay: ISwimBehavior
{
  public void swim()
  {
    Console.WriteLine("泳げないよ...");
  }
}
```

### 飛ぶ(fly)行動
飛ぶ行動のインターフェースに、それぞれ飛ぶ「Fly」クラス、飛ばない「FlyNoWay」クラスを実装する。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/ce9f0272-f712-c5d2-f7d9-c05144987fab.png" width="400" />
```c# 
public interface IFlyBehavior
{
  void swim();
}

public Fly: IFlyBehavior
{
  public void fly()
  {
    // 本当はここに飛ぶ動作を実装します
    Console.WriteLine("飛べるぜ");
  }  
}

public FlyNoWay: IFlyBehavior
{
  public void fly()
  {
    Console.WriteLine("飛べないよ...");
  }
}
```

## 行動をもったアヒルクラス
### Baseアヒル
displayは共通の処理、それ以外は実装された行動を呼び出します。
そしてこのアヒルはガーガー鳴くし、泳げるけど、飛べないアヒルとして定義します。
```c#
public class Duck
{
  IQuackBehavior quackBehavior;
  ISwimBehavior swimBehavior;
  IFlyBehavior flyBehavior;

  public Duck()
  {
    quackBehavior = new Quack();
    swimBehavior = new Swim();
    flyBehavior = new FlyNoWay();
  }
  public void display()
  {
    // 本当はここにアヒルを表示する処理を実装する
    Console.WriteLine("アヒルを表示する");
  }
  
  public void quack()
  {
    quackBehavior.quack();
  }

  public void swim()
  {
    swimBehavior.swim();
  }

  public void fly()
  {
    flyBehavior.fly();
  }
}
```

### マガモクラス
このマガモはガーガー鳴くし、普通に泳ぐし、普通に飛べるアヒルとして定義します。
```c#
public class MallardDuck: Duck
{
  public MallardDuck()
  {
    quackBehavior = new Quack();
    swimBehavior = new Swim();
    flyBehavior = new Fly();
  }
}
```

### ゴム製アヒルのおもちゃクラス
このアヒルのおもちゃはキュッキュッと泣き、泳げないし、飛べないアヒルとして定義します。
```c#
public class RubberDuck: Duck
{
  public RubberDuck()
  {
    quackBehavior = new Quack();
    swimBehavior = new SwimNoway();
    flyBehavior = new FlyNoWay();
  }
}
```

以上によって、アヒルの行動が定義でき、それぞれのクラスを作成することができました。
ただ、今回進化することによってアヒルの行動が変わるといことを想定していましたので、Baseアヒルクラスに行動を変更するメソッドを定義しておきます。

```c#
public void setQuackBehavior(IQuackBehavior qb)
{
  quackBehavior = qb;
}
public void setSwimBehavior(ISwimBehavior sb)
{
  swimBehavior = sb;
}
public void setFlyBehavoir(IFlyBehavior fb)
{
  flyBehavior = fb;
}
```
これによって、進化する際に行動を変更することができるようになりました。

# 参考文献
https://www.oreilly.co.jp/books/9784873119762/

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516848/e5034cf2-18e6-a5eb-c4d8-c4e9d76e13d2.png" width="300" />