SOLID原則 - インターフェイス分離の原則

## 概要
グループでSOLID原則とは何かを学んだので、その内容を記載します。
本記事では、SOLID原則の「インターフェイス分離の原則」について説明します。

### SOLID原則とは？
オブジェクト指向で用いられる以下5つの原則のことです。
* **S**ingle Responsibility Principle (単一責任の原則)
* **O**pen-Closed Principle (オープン・クローズドの原則)
* **L**iskov Substitution Principle (リスコフの置換原則)
* **I**nterface Segregation Principle (インターフェイス分離の原則) ←本記事の内容
* **D**ependency Inversion Principle (依存関係逆転の原則)

変更に強く、理解しやすいソフトウェアを作るための基本原則です。


## インターフェイス分離の原則
インターフェイス実装先で使わないメソッドがないようにインターフェイスをわけること。

### 原則を守らないとどうなるか？
クラスに使用することのできないメソッドを定義できるため、
無駄なコードになるだけでなく、予期しないバグ発生に繋がる可能性があります。

### 原則を守った実装方法
1\. 必要最小限の機能を持つようにインターフェイスを作成する
2\. クラスに必要なインターフェイスを適切に実装する

#### 具体的には...
「剣士」と「魔法使い」がいるとします。
「剣士」は移動、剣を使った攻撃、守りができます。
「魔法使い」は移動、魔法攻撃、守りができます。

```plantuml
class 剣士{
  - 移動
  - 剣を使った攻撃
  - 守り
}
@enduml
```
```plantuml
class 魔法使い
{
  - 移動
  - 魔法攻撃
  - 守り
}
@enduml
```

必要なメソッドは、移動、剣を使った攻撃、守り、魔法攻撃の4つになります。
　
 
**❌先にダメな例**

移動、剣を使った攻撃、守り、魔法攻撃の4つのメソッドを持つインターフェイスを作成。
剣士、魔法使いが上記のインターフェイスを実装すると...

```plantuml
class 剣士
class 魔法使い
interface 共通{
  - 移動
  - 剣を使った攻撃
  - 魔法攻撃
  - 守り
}

剣士 --|> 共通
魔法使い --|> 共通

@enduml
```
魔法使いが剣を使った攻撃をできる！剣士が魔法を使える！といった意図しない動きができてしまいます。

　
**⭕️正しい実装**

まずは、**インターフェイスの分離**を行います。
必要最小限のメソッドを持つようにインターフェイスを作成するので、今回の例では以下のようになります。

①剣士と魔法使いに共通する処理を持つインターフェイス：移動、守り
```plantuml
interface ①共通インターフェイス{
  - 移動
  - 守り
}
@enduml
```
②剣士のインターフェイス：剣を使った攻撃
```plantuml
interface ②剣士のインターフェイス{
  - 剣を使った攻撃
}
@enduml
```

③魔法使いのインターフェイス：魔法攻撃
```plantuml
interface ③魔法使いのインターフェイス{
  - 魔法攻撃
}

@enduml
```
　
次に、**クラスに必要なインターフェイスを適切に実装**します。
剣士と魔法使いが漏れなく処理を行えるようにするには、先ほど分割した3つのインターフェイスを以下のように実装します。

剣士：①共通インターフェイス(移動、守り)、②剣士のインターフェイス(剣を使った攻撃)
```plantuml
interface ①共通インターフェイス{
  - 移動
  - 守り
}

interface ②剣士のインターフェイス{
  - 剣を使った攻撃
}

剣士 --|> ①共通インターフェイス
剣士 --|> ②剣士のインターフェイス

@enduml
```

魔法使い：①共通インターフェイス(移動、守り)、③魔法使いのインターフェイス(魔法攻撃)
```plantuml
interface ①共通インターフェイス{
  - 移動
  - 守り
}

interface ③魔法使いのインターフェイス{
  - 魔法攻撃
}

魔法使い --|> ①共通インターフェイス
魔法使い --|> ③魔法使いのインターフェイス

@enduml
```

このように、必要最低限の状態にインターフェイスを分け、必要な処理をもつインターフェイスを適切に実装するのがインターフェイス分離の原則です。
原則が守られていると、意図しないバグを防げるだけでなく、理解しやすく変更に強いコードにもなります！


##### 各インターフェイスで共通インターフェイスを継承
今回の例では、各クラスが共通インターフェイスと専用インターフェイスをそれぞれ実装していますが、共通インターフェイスを継承した専用インターフェイスを実装する方法もあります。

```plantuml
interface ①共通インターフェイス{
  - 移動
  - 守り
}

interface ②剣士のインターフェイス{
  - 剣を使った攻撃
}

interface ③魔法使いのインターフェイス{
  - 魔法攻撃
}


剣士 --|> ②剣士のインターフェイス
②剣士のインターフェイス --|> ①共通インターフェイス

魔法使い --|> ③魔法使いのインターフェイス
③魔法使いのインターフェイス --|> ①共通インターフェイス

@enduml
```
「共通インターフェイスと専用インターフェイスをそれぞれ実装する方法」と「共通インターフェイスを継承した専用インターフェイスを実装する方法」どちらが正しいかは「場合による」みたいです。
どのような場合にどちらの方法を選択すべきか、今後グループで話し合い理解を深めていきたいです。


## 参考
* [Clean Code アジャイルソフトウェア達人の技](https://www.amazon.co.jp/Clean-Code-%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%81%94%E4%BA%BA%E3%81%AE%E6%8A%80-Robert-C-Martin/dp/4048930591/ref=pd_vtp_h_pd_vtp_h_d_sccl_4/358-3755681-0356521?pd_rd_w=lUUv2&content-id=amzn1.sym.a075abab-259f-40c3-bc0f-76d5f3149ef5&pf_rd_p=a075abab-259f-40c3-bc0f-76d5f3149ef5&pf_rd_r=QW6XVZC6VJG155QENZA8&pd_rd_wg=yP7Nx&pd_rd_r=1d275eed-97be-48f9-84a2-b9ece9468928&pd_rd_i=4048930591&psc=1)(書籍)
* [現実世界の事象から学ぶSOLID原則 by ほりしょー](https://fortee.jp/oocon-2024/proposal/e1eb34cf-78ef-43f6-8a03-bb26c996cb62)
* [【SOLID】インターフェース分離の原則を完全に理解したい](https://qiita.com/k2491p/items/7b4e56789964ac6328b3)
* [マリオで学ぶSOLID原則](https://zenn.dev/keiichiro/articles/9397379ab638b1)