解答 01.4 — インターフェース(SlackNotifier)¶
このノートブックは 01.4-interfaces-abstraction-polymorphism.ipynb の練習問題の解答です。
先に自分の力で解いてから、答え合わせに使ってください。
前提コード(問題ノートブックと同じ定義)¶
In [1]:
import "fmt"
In [2]:
type Notifier interface {
Notify(message string) error
}
type EmailNotifier struct {
address string
}
func (n EmailNotifier) Notify(message string) error {
fmt.Printf("[Email → %s] %s\n", n.address, message)
return nil
}
func SendAlert(n Notifier, message string) error {
return n.Notify(message)
}
解答: SlackNotifier¶
Notify を正しいシグネチャで実装すれば、SlackNotifier は自動的に Notifier を満たします。
メッセージの記録(messages への追加)も行います。
In [3]:
type SlackNotifier struct {
channel string
messages []string
}
func (s *SlackNotifier) Notify(message string) error {
s.messages = append(s.messages, message)
fmt.Printf("[Slack → %s] %s\n", s.channel, message)
return nil
}
// コンパイル時に SlackNotifier が Notifier を満たすことを確認する
var _ Notifier = (*SlackNotifier)(nil)
チェック(問題ノートブックと同じ期待値)¶
In [4]:
import "reflect"
import "fmt"
func mustEqual(got, want any, name string) {
if reflect.DeepEqual(got, want) {
fmt.Printf("✅ Passed: %s\n", name)
return
}
panic(fmt.Sprintf("❌ %s\n got = %v (%T)\n want = %v (%T)", name, got, got, want, want))
}
In [5]:
%%
slack := &SlackNotifier{channel: "#general"}
err := SendAlert(slack, "障害発生")
mustEqual(err, nil, "SendAlert がエラーなし")
mustEqual(slack.messages, []string{"障害発生"}, "メッセージが記録された")
mustEqual(len(slack.messages), 1, "1 件だけ記録")
println("🎉 すべてのチェックが通りました")
[Slack → #general] 障害発生 ✅ Passed: SendAlert がエラーなし
✅ Passed: メッセージが記録された ✅ Passed: 1 件だけ記録
🎉 すべてのチェックが通りました
解説¶
func (s *SlackNotifier) Notify(message string) error—Notifierと同じシグネチャを持つことで、*SlackNotifierは自動的にNotifierを満たします(ダックタイピング)s.messages = append(s.messages, message)— 送ったメッセージを記録しますvar _ Notifier = (*SlackNotifier)(nil)— コンパイル時の保証です。もしNotifyのシグネチャがズレていたら、この行がコンパイルエラーになります。「シグネチャが一致しているか」を自分で数える代わりに、コンパイラに確認させるイディオムです
SendAlert は Notifier にしか依存していないので、SlackNotifier を追加しても呼び出し側を一切変更していません。これが抽象化の効果です。