「なぜインターフェースを使わないといけないんですか？」という疑問に頑張って回答する

## はじめに
「オブジェクト指向のインターフェースは知っているが，重要性や具体的な使い所がわからない」という方に向け，私なりにインターフェースの重要性について説明します。

## インターフェースの意義
インターフェースはコードの可読性を高め、将来のメソッド実装を保証することで、変更しやすいコードベースの作成に貢献します．

以下2点の具体的なメリットについて解説していきます．
1. 条件分岐(if文， switch文)の削減による可読性の向上
2. 将来のメソッド実装を保証

## if文やswitch文の削減による可読性の向上
コードが増える場合，if文やswitch文の削減が重要になってきます．
ソフトウェアは，様々な場所で状態や設定に応じた処理の分岐が発生します．
しかし，コードは分岐が増えるほど，複雑で理解しづらくなります．

そこで，インターフェースを使えば，if文やswitch文を書かずに処理を分岐できます．
インターフェース型の変数に，異なるクラスのインスタンスを代入することで，異なる処理を呼び出すことができます．

例として，ポケモンの「わざ」を発動する処理について考えてみましょう．
今回実装する「わざ」は次の3つです．
> - ひのこ
>    - タイプ:  ほのおタイプ
>    - 威力：40
>    - 追加効果:  10%の確率でやけど状態にする
> - あわ
>    - タイプ:  みずタイプ
>    - 威力：40
>    - 追加効果:  なし
> - すいとる
>    - タイプ: くさタイプ
>    - 威力：20
>    - 追加効果:  与えたダメージ分HPを回復する

今回の主題は「追加効果の処理をどう分岐するか」です．

まずはSwitch文で追加効果について分岐して，「わざ」を取り扱うクラス(`Move`)クラスを実装してみます．
以下の折りたたみブロックに実装例を示します．

<details><summary>Switch文で実装した例</summary>

```Go
package main

import (
	"fmt"
	"math/rand"
	"time"
)

type Move struct {
	Name       string
	Type       string
	Power      int
	Additional string
}

func (m Move) execute() {
	fmt.Printf("%s (%s) with power %d is activated.\n", m.Name, m.Type, m.Power)

	switch m.Additional {
	case "burn":
         // 乱数生成
    	rand.Seed(time.Now().UnixNano())
		if rand.Intn(100) < 10 { // 10% の確率
			fmt.Println("The target is burned!")
		} else {
			fmt.Println("No additional effect.")
		}
	case "drain":
		healedAmount := m.Power // 単純化のため，攻撃力と回復量を一緒にしている
		fmt.Printf("The user recovers %d HP!\n", healedAmount)
	case "none":
		fmt.Println("No additional effect.")
	default:
		fmt.Println("Unknown additional effect.")
	}
}

func main() {
	moves := []Move{
		{"ひのこ", "ほのおタイプ", 40, "burn"},
		{"あわ", "みずタイプ", 40, "none"},
		{"すいとる", "くさタイプ", 20, "drain"},
	}

	for _, move := range moves {
		fmt.Println("Using move:", move.Name)
		move.execute()
	}
}
```

</details>


このコードは動作しますが，executeメソッドにswitch文の分岐があり，「ひのこ」の処理について知りたい人の目にも，「あわ」「すいとる」の処理も入ってきます．
「わざ」の数が増えるにつれて目に入る処理の数は増えていくでしょう．
こういった場合，インターフェースを使って可読性を向上できます．

では，追加効果インターフェース(`EffectApplier`)とそれを実装した`Burn`クラス，`Drain`クラス，`None`クラスを実装してみましょう．
以下の折りたたみブロックにインターフェースを使用した実装例を示します．

<details><summary>インターフェースで実装した例</summary>

```Go
package main

import (
	"fmt"
	"math/rand"
	"time"
)

// 追加効果インターフェース
type EffectApplier interface {
	Activate()
}

// やけど
type Burn struct{}

func (b Burn) Activate() {
	rand.Seed(time.Now().UnixNano())
	if rand.Intn(100) < 10 { // 10%でやけど状態にする
		fmt.Println("The target is burned!")
	} else {
		fmt.Println("No additional effect.")
	}
}

// HP吸収
type Drain struct {
	Amount int
}

func (d Drain) Activate() {
	fmt.Printf("The user recovers %d HP!\n", d.Amount)
}

// 何もしない
type None struct{}

func (n None) Activate() {
	fmt.Println("No additional effect.")
}

// 「わざ」クラス
type Move struct {
	Name       string
	Type       string
	Power      int
	Effect     EffectApplier
}

// 「わざ」の発動
func (m Move) execute() {
	fmt.Printf("%s (%s) with power %d is activated.\n", m.Name, m.Type, m.Power)
	m.Effect.Activate()
}

func main() {
	moves := []Move{
		{"ひのこ", "ほのおタイプ", 40, Burn{}},
		{"あわ", "みずタイプ", 40, None{}},
		{"すいとる", "くさタイプ", 20, Drain{Amount: 20}},
	}

	for _, move := range moves {
		fmt.Println("Using move:", move.Name)
		move.execute()
	}
}
```

</details>


インターフェースを使用することで，分岐が減って，`execute`メソッドの見通しがよくなりました．
記事の都合上，全てのクラス，インターフェースを一箇所に記述しているためコード量は増えています．
しかし，各クラスを別ファイルに分ければ，一つの「わざ」の処理を理解するために読むコード量は減ります．

インターフェースの使用はコードの単純化と可読性を向上させ，ソフトウェアの変更を容易にし，作業効率の向上とコスト削減に寄与します．

## 将来のメソッド実装を保証
インターフェースを使うことで，将来のメソッド実装を保証できます．

ポケモンの「わざ」に「10まんボルト」が追加された場合について考えてみましょう．
10まんボルトの仕様は以下のようなものです．
> - 10まんボルト
>    - タイプ:  でんきタイプ
>    - 威力：90
>    - 追加効果:  10%の確率で相手をまひ状態にする

実装担当者が追加効果の実装を忘れた場合に，インターフェースを使用した実装はエラーを発生させることができます．
インターフェースを使用した実装では,`EffectApplier`の実装(`Activate`メソッドの実装)を忘れるとコンパイルエラーが発生し,コンパイル時に実装ミスが検出されます.
一方，switch文を使用すると，default処理が実行されてエラーが表示されないため，実装ミスが検出されにくいです．

このように，インターフェースはバグを予防する効果があり，ビジネスのリスクを削減できます．

## さらなる勉強におすすめな書籍
インターフェースの重要性についてより詳しくなるために，おすすめの書籍を最後に紹介します．
この記事もこちらの書籍の受け売りな部分があるので，この記事に興味を持っていただけた方なら，楽しく学べるでしょう．

### 良いコード/悪いコードで学ぶ設計入門 ―保守しやすい 成長し続けるコードの書き方
私の記事よりもifやswitchで分岐する実装の悪い点について丁寧に説明しており，インターフェースの重要性がより詳しく記載されています．
さらに，ここで述べた以外にも変更が容易なコードベースに貢献するためのスキルにも触れられています．
設計の本は理解が難しいものが多い中で，初学者にもおすすめの一冊です．

[amazonリンク](https://amzn.asia/d/i2Bva1F)