【C#】Head First デザインパターンでオブジェクト指向の勉強


##デザインパターン1章

https://www.oreilly.co.jp/books/4873112494/

一番わかりやすく読みやすかったのでこの本でオブジェクト指向を勉強していきます。今回は一章のアヒルの例です。
マガモやゴムアヒルを作るのに基本となるアヒルクラスを作って継承させるのはどう？？というのから始まってそれじゃだめだからインターフェイスで。

```plantuml
interface Flyable

interface Quackable
class Duck
{
swim()
display()
}
class MallardDuck
{
display()
fly()
quack()
}
class RubberDuck
{
display()
fly()
quack()
}

Flyable <|.. MallardDuck
Flyable <|.. RubberDuck
Quackable <|.. MallardDuck
Quackable <|.. RubberDuck
Duck <|-- MallardDuck
Duck <|-- RubberDuck
```
この形でも作るアヒルによってFlyableの中身を書いてあげないといけないから結局メンテが大変。ゴムのアヒルはそもそも飛べない。

```plantuml
package Main {
  class Duck {
    飛ぶ挙動: FlyBehavior
    鳴く挙動: QuackBehavior
    swim()
    display()
    performQuack()
    performFly()
    setFlyBehavior(飛ぶ挙動: FlyBehavior)
    setQuackBehavior(鳴く挙動: QuackBehavior)
  }
  class MallardDuck {
    display()  // マガモの表示
  }
  class RubberDuck {
    display()  // ゴム製の鴨の表示
  }
}
package カプセル化された飛ぶ挙動 {
 together {
  interface FlyBehavior {
    fly()
  }
  class FlyWithWing {
    fly()  // 鴨の飛行を実装
  }
  class FlyNoWay {
    fly()  // 何もしない、飛べない
  }
 }
}
package カプセル化された鳴く挙動 {
 together {
  interface QuackBehavior {
    quack()
  }
  class Quack {
    quack()  // 鴨の鳴き声を実装
  }
  class Squeak {
     quack()  // ゴム製の鳴き
  }
 }
}
FlyWithWing --[hidden] QuackBehavior
Duck <|-- MallardDuck
Duck <|-- RubberDuck
Duck -> FlyBehavior
FlyBehavior <|.. FlyWithWing
FlyBehavior <|.. FlyNoWay
Duck -> QuackBehavior
QuackBehavior <|.. Quack
QuackBehavior <|.. Squeak
```

それならFlyBehaviorという名前のインターフェイスを作ってカプセル化してあげれば変更に強くなるので動的に挙動を変えることもできるかも！？というお話です。ここでは翼で飛ぶまたは飛べないというクラスを作ってマガモであれば飛ぶという選択を、ゴムアヒルであれば飛べないという挙動を選ぶことができる。

```CS:Program.cs
using System;

namespace HeadFirstEx1
{
    class Program
    {
        static void Main(string[] args)
        {
            MallardDuck mallard = new MallardDuck();
            mallard.performFly();
            mallard.performQuack();

            RubberDuck rubber = new RubberDuck();
            rubber.performFly();
            rubber.performQuack();
        }
    }

    public abstract class Duck
    {
        public FlyBehavior flyBehavior;
        public QuackBehavior quackBehavior;

        public Duck()
        {

        }
        public abstract void display();

        public void setFlyBehavior(FlyBehavior fb)
        {
            flyBehavior = fb;
        }
        public void performFly()
        {
            flyBehavior.fly();
        }

        public void setQuackBehavior(QuackBehavior qb)
        {
            quackBehavior = qb;
        }

        public void performQuack()
        {
            quackBehavior.quack();
        }
        public void swim()
        {
            Console.WriteLine("Swim");
        }
    }

    public interface FlyBehavior
    {
        void fly();
    }

    public class FlyWithWings : FlyBehavior
    {
        public void fly()
        {
            Console.WriteLine("I am flying.");
        }
    }
    public class FlyNoWay : FlyBehavior
    {
        public void fly()
        {
            Console.WriteLine("I cannot fly.");
        }
    }

    public interface QuackBehavior
    {
        void quack();
    }

    public class Quack:QuackBehavior
    {
        public void quack()
        {
            Console.WriteLine("Quack");
        }
    }

    public class Squeak : QuackBehavior
    {
        public void quack()
        {
            Console.WriteLine("Squeak");
        }
    }

    public class MuteQuack : QuackBehavior
    {
        public void quack()
        {
            Console.WriteLine("<< Silence >>");        
        }
    }
    public class MallardDuck: Duck
    {
        public MallardDuck()
        {            
            setFlyBehavior(new FlyWithWings());
            setQuackBehavior(new Quack());
        }

        public override void display()
        {
            Console.WriteLine("I am a MallardDuck");
        }
    }

    public class RubberDuck : Duck
    {
        public RubberDuck()
        {       
            setFlyBehavior(new FlyNoWay());
            setQuackBehavior(new Squeak());
        }

        public override void display()
        {
            Console.WriteLine("I am a rubber duck");
        }
    }
}
```
結果はこのようになります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64828/2d34360a-c3a5-feae-6d6d-cb34d3ab6839.png)

もともとは飛ばないゴムアヒルを無理やり飛ばすにはこのようにsetFlyBehaviorにFlyWithWingsクラスを与えてやると飛びます。

```cs
static void Main(string[] args)
        {
            MallardDuck mallard = new MallardDuck();
            Console.WriteLine("MallardDuck");
            mallard.performFly();
            mallard.performQuack();
            Console.WriteLine("RubberDuck");
            RubberDuck rubber = new RubberDuck();
            rubber.performFly();
            rubber.performQuack();
            Console.WriteLine("------------------------");
            rubber.setFlyBehavior(new FlyWithWings());
            rubber.performFly();
        }
```
しっかりと飛べました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64828/d69c69dc-3a03-1d1f-840c-d130307eb467.png)


次回は2章です。

###追記
@shiracamus さんよりインターフェース使用方向の指摘、plantUML図の編集をしていただきました。ありがとうございます。