Verbergen eingebetteter Methoden
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 39 von 107.
Manchmal muss die äußere Struktur eine eigene Implementierung einer Methode bereitstellen, die der eingebettete Typ bereits besitzt. Dies wird als Überschattung bezeichnet und ermöglicht es dir, promovierte Methoden mit einem benutzerdefinierten Verhalten zu überschreiben.
Wenn du eine Methode für die äußere Struktur mit demselben Namen wie eine eingebettete Methode definierst, hat die äußere Methode Vorrang:
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!"
}
Wenn du jetzt Speak() für einen Dog aufrufst, wird die äußere Methode verwendet:
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof! - Methode von Dog
fmt.Println(d.Animal.Speak()) // Irgendein Geräusch - Methode von Animal
}
Die eingebettete Methode ist nicht verschwunden. Du kannst weiterhin explizit über den Namen des eingebetteten Typs auf sie zugreifen. Dieses Muster ist nützlich, wenn du das Verhalten anpassen und gleichzeitig die ursprüngliche Implementierung verfügbar halten möchtest, etwa um sie innerhalb deiner überschreibenden Methode aufzurufen:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
Shadowing gibt dir die Kontrolle darüber, welches Verhalten offengelegt wird, während du über eine explizite Qualifizierung weiterhin auf das ursprüngliche Verhalten zugreifen kannst.
Aufgabe
EinfachWir erstellen ein Benachrichtigungssystem, in dem verschiedene Benachrichtigungskanäle anpassen können, wie sie Nachrichten formatieren und zustellen. Du verwendest Methoden-Shadowing, damit bestimmte Kanäle das Standardverhalten überschreiben können und bei Bedarf trotzdem auf die ursprüngliche Implementierung zugreifen können.
Du organisierst deinen Code über drei Dateien:
base.go: Erstelle eineBaseNotification-Struktur mit den FeldernTitleundPriority(beide vom Typ String). Gib ihr eine MethodeFormat() string, die die Benachrichtigung in einem Standardformat zurückgibt:[Priority] Title.channels.go: Erstelle zwei Typen für Benachrichtigungskanäle, dieBaseNotificationeinbetten und die MethodeFormatmit eigenen Implementierungen überschreiben:EmailNotificationmit einem FeldRecipient. Die MethodeFormat()sollEmail to [Recipient]: [Priority] Titlezurückgeben.SlackNotificationmit einem FeldChannel. Die MethodeFormat()soll die eingebettete MethodeBaseNotification.Format()aufrufen und dem Ergebnis#[Channel]:voranstellen.
main.go: Lies die Benachrichtigungsdetails aus der Eingabe, erstelle beide Benachrichtigungstypen und veranschauliche das Methoden-Shadowing, indem du Folgendes ausgibst:- Die formatierte Ausgabe von
EmailNotification(unter Verwendung seiner überschriebenen Methode) - Das Basisformat von
EmailNotification(durch explizites Aufrufen der eingebetteten Methode) - Die formatierte Ausgabe von
SlackNotification(die intern die Basismethode verwendet)
- Die formatierte Ausgabe von
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Titel der Benachrichtigung
- Zeile 2: Prioritätsstufe
- Zeile 3: E-Mail-Empfänger
- Zeile 4: Name des Slack-Kanals
Wenn beispielsweise Server Alert, HIGH, admin@company.com und ops-alerts angegeben werden, sollte deine Ausgabe wie folgt aussehen:
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server AlertBeachte, wie EmailNotification die Formatierung der Basis vollständig ersetzt, während SlackNotification sie durch den Aufruf der ursprünglichen Methode und das Hinzufügen des Kanalkontexts erweitert. Beide Ansätze veranschaulichen unterschiedliche Möglichkeiten, Methoden-Shadowing effektiv einzusetzen.
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Benachrichtigungstitel lesen
scanner.Scan()
title := scanner.Text()
// Prioritätsstufe lesen
scanner.Scan()
priority := scanner.Text()
// E-Mail-Empfänger lesen
scanner.Scan()
recipient := scanner.Text()
// Slack-Kanalnamen lesen
scanner.Scan()
channel := scanner.Text()
// TODO: Erstelle eine EmailNotification mit der Basis-Benachrichtigung, title, priority und recipient
// TODO: Erstelle eine SlackNotification mit der Basis-Benachrichtigung, title, priority und channel
// TODO: Gib die formatierte Ausgabe der EmailNotification aus (unter Verwendung ihrer überschatteten Methode)
// TODO: Gib das Basisformat der EmailNotification aus (expliziter Aufruf der eingebetteten Methode)
// TODO: Gib die formatierte Ausgabe der SlackNotification aus
fmt.Println() // Platzhalter - bei Implementierung entfernen
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP in Go
Externe DateienGo-Workspace & ModulePackages & ImportsExportierte vs. nicht exportierte NamenEinführung in OOP mit GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktorfunktionenRückblick – Einfacher Taschenrechner4Schnittstellen
Einführung in SchnittstellenImplizite ImplementierungSchnittstelle als VertragLeere Schnittstelle (any)TypzusicherungTypwechselZusammensetzung von SchnittstellenStringer- und Error-SchnittstellenRückblick – Formenrechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf PaketebeneGetter- und Setter-MethodenInformationsverbergung in GoRückblick – Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterTypbeschränkungenGenerische StrukturenWorkaround für generische MethodenZusammenfassung – Generische Sammlung2Typen & Structs im Detail
Grundlegende & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct-TagsAnonyme StructsVerschachtelte StructsNullwerte & StandardwerteRückblick – Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen der Struct-EinbettungMethoden-PromotionMehrere Structs einbettenEinbettung vs. AggregationVerbergen eingebetteter MethodenRückblick – Mitarbeiterhierarchie8Fehlerbehandlung & OOP
Das Error-InterfaceBenutzerdefinierte FehlertypenError-Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverRückblick – Dateiparser3Zeiger & Speicher
Grundlagen von Zeigern in GoZeiger auf StructsÜbergabe per Wert vs. ReferenzDie Funktion new()Garbage Collection in GoRückblick – Verkettete Liste erstellen6Polymorphismus in Go
Polymorphismus über InterfacesDuck-Typing in GoRegeln zur Interface-ErfüllungPolymorphe SammlungenDependency InjectionZusammenfassung – Zahlungsprozessor9Konkurrenz & OOP
Grundlagen der GoroutinesChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignRückblick – Worker PoolÜbe selbstständig: Online-Go-Compiler