🔥
Goのインターフェースについて
インターフェースとは
特定のメソッドの集合を定義する型。Structなどで定義された具体的な型がそのインターフェースを実装するかどうかが判定される。
何がいいのか?
インターフェースを使用しなければ、コードの管理が複雑になってしまう恐れがある。インターフェースを使用しなかった場合と、使用した場合のコードを比較する。
とあるWebアプリの機能で通知機能を実装することになった。SMSとEmailの両方で通知を送信する要件とする。
- インターフェースを使用しなかった場合
package main
import "fmt"
func SendEmailNotification(emailAddress string, message string) {
fmt.Println("Sending email to", emailAddress, ":", message)
}
func SendSMSNotification(phoneNumber string, message string) {
fmt.Println("Sending SMS to", phoneNumber, ":", message)
}
func main() {
SendEmailNotification("example@example.com", "Hello via Email!")
SendSMSNotification("123-456-7890", "Hello via SMS!")
}
問題点
- コードの重複:各通知方法に対して、ほぼ同じ内容のコードを繰り返し書く必要がある。今後通知方法を増やすと関数の数が増え、重複したコードも増える。
- 拡張性の低さ:新しい通知方法を追加する場合、既存のコードに新しい関数を追加し、さらに処理を増やす必要がある。
- 保守性の低さ:各関数が独立しているため、共通処理に変更があった場合、すべての関数を個別に修正する必要がある。
- Interfaceを使用した場合
package main
import "fmt"
type Notifier interface {
Notify() string
}
type EmailNotifier struct {
emailAddress string
message string
}
func (e EmailNotifier) Notify() string {
return fmt.Sprintf("Sending email to %s: %s\n", e.emailAddress, e.message)
}
type SMSNotifier struct {
phoneNumber string
message string
}
func (s SMSNotifier) Notify() string {
return fmt.Sprintf("Sending SMS to %s: %s\n", s.phoneNumber, s.message)
}
func main() {
notifications := []Notifier{
EmailNotifier{emailAddress: "example@example.com", message: "Hello via Email!"},
SMSNotifier{phoneNumber: "123-456-7890", message: "Hello via SMS!"},
}
for _, n := range notifications {
fmt.Println(n.Notify())
}
}
メリット
- コード再利用性の向上:Notifierインターフェース型のスライスを使用して、さまざまな通知を一度に行えるようになる。
-
拡張性の向上:新しい通知方法を追加する場合、
Notifierインターフェースを実装した新しい型を作成するだけで、新しい通知方法を簡単に追加できる。 -
保守性の向上:すべての通知方法が
Notifyメソッドを通じて統一的に処理されるため、共通の通知処理が変更される場合でも、インターフェースを実装した型だけ修正すれば良い。 - テスト容易性:インターフェースを使用すると、モックを作成してテストが簡単になる。go-mockなどを使用して、モックの生成も容易になる。
まとめ
| 特徴 | インターフェースあり | インターフェースなし |
|---|---|---|
| コードの重複 | 最小限(共通のインターフェースを使い回し) | 通知方法ごとに個別の関数が必要 |
| 拡張性 | 高い(新しい通知方法を簡単に追加) | 低い(通知方法が増えるたびに新しい関数が必要) |
| 保守性 | 高い(共通処理の修正が容易) | 低い(変更が必要な場合、複数の関数を修正) |
| 可読性 | 高い(統一されたインターフェースで整理) | 低い(個別の関数で複雑になりやすい) |
| テストの容易さ | 高い(モックを使ったテストが可能) | 低い(テスト用のコードが冗長) |
Discussion