埋め込まれたメソッドのシャドウイング
CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 39/107。
埋め込み型がすでに持っているメソッドについて、外側の構造体に独自の実装を提供させる必要がある場合があります。これはシャドーイングと呼ばれ、昇格されたメソッドをカスタム動作でオーバーライドできます。
外側の構造体で embedded method と同じ名前の method を定義すると、外側の method が優先されます:
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
ここで、Dog に対して Speak() を呼び出すと、外側のメソッドが使用されます。
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - Dogのメソッド
fmt.Println(d.Animal.Speak()) // Some sound - Animalのメソッド
}
埋め込みメソッドはなくなったわけではありません。埋め込み型の名前を使えば、今でも明示的にアクセスできます。このパターンは、元の実装を利用できる状態に保ちながら動作をカスタマイズしたい場合に便利です。たとえば、オーバーライドするメソッド内から呼び出すことができます。
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
シャドーイングを使うと、明示的な修飾によって元の動作にアクセスしながら、どの動作を公開するかを制御できます。
チャレンジ
簡単異なる notification channel がメッセージの format と配信方法をカスタマイズできる notification system を構築しましょう。method shadowing を使って、特定の channel がデフォルトの動作をオーバーライドしつつ、必要なときには元の実装にもアクセスできるようにします。
コードを3つのファイルに分けて整理します。
base.go:TitleとPriorityの fields(どちらも文字列)を持つBaseNotificationstruct を作成します。notification を標準的な format で返すFormat() stringmethod を定義します:[Priority] Title。channels.go:BaseNotificationを embed し、独自の実装でFormatmethod を shadow する2つの notification channel 型を作成します。EmailNotification:Recipientfield を持ちます。そのFormat()はEmail to [Recipient]: [Priority] Titleを返します。SlackNotification:Channelfield を持ちます。そのFormat()は埋め込まれたBaseNotification.Format()method を呼び出し、結果の先頭に#[Channel]:を付加します。
main.go: 入力から notification の詳細を読み取り、両方の型の notification を作成し、次の内容を出力して shadowing を示します。EmailNotificationの formatted output(その shadow された method を使用)EmailNotificationの base format(埋め込まれた method を explicitly に呼び出す)SlackNotificationの formatted output(内部で base method を使用)
次の入力が提供されます。
- 1行目: notification のタイトル
- 2行目: Priority level
- 3行目: Email recipient
- 4行目: Slack channel name
たとえば、Server Alert、HIGH、admin@company.com、ops-alerts が与えられた場合、output は次のようになります。
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server AlertEmailNotification は base の format を完全に置き換える一方、SlackNotification は元の method を呼び出して channel の context を追加することで拡張していることに注目してください。どちらのアプローチも、method shadowing を効果的に使用する異なる方法を示しています。
自分で試してみよう
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 通知タイトルを読み取る
scanner.Scan()
title := scanner.Text()
// 優先度レベルを読み取る
scanner.Scan()
priority := scanner.Text()
// メール受信者を読み取る
scanner.Scan()
recipient := scanner.Text()
// Slackチャンネル名を読み取る
scanner.Scan()
channel := scanner.Text()
// TODO: ベース通知、title、priority、recipientを使ってEmailNotificationを作成する
// TODO: ベース通知、title、priority、channelを使ってSlackNotificationを作成する
// TODO: EmailNotificationのフォーマット済み出力を表示する(シャドウされたメソッドを使用)
// TODO: EmailNotificationのベースフォーマットを表示する(埋め込みメソッドを明示的に呼び出す)
// TODO: SlackNotificationのフォーマット済み出力を表示する
fmt.Println() // プレースホルダー - 実装時に削除する
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1Go オブジェクト指向の基礎
外部ファイルGo ワークスペースとモジュールパッケージとインポート公開された名前と非公開の名前Go におけるオブジェクト指向入門クラスとしての構造体構造体へのメソッド定義ポインタレシーバと値レシーバ構造体の初期化コンストラクタ関数まとめ:簡易計算機8エラー処理とOOP
error インターフェースカスタムエラー型エラーラッピング (fmt.Errorf)センチネルエラーerrors.Is() と errors.As()Panic、Defer、Recover復習 - ファイルパーサー自分で練習してみよう: Goオンラインコンパイラ