Method Chaining
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 81 von 107.
Method Chaining ist eine Technik, bei der Methoden den Empfänger zurückgeben, sodass mehrere Methodenaufrufe in einer einzigen Anweisung miteinander verknüpft werden können. Du hast dies bereits beim Builder-Muster gesehen, aber es handelt sich um ein eigenständiges Konzept, das in vielen Kontexten nützlich ist.
Der key besteht darin, aus jeder Methode einen Zeiger auf die Struktur zurückzugeben:
type Query struct {
table string
columns []string
where string
limit int
}
func (q *Query) Select(cols ...string) *Query {
q.columns = cols
return q
}
func (q *Query) From(table string) *Query {
q.table = table
return q
}
func (q *Query) Where(condition string) *Query {
q.where = condition
return q
}
func (q *Query) Limit(n int) *Query {
q.limit = n
return q
}Jetzt kannst du diese Aufrufe flüssig verketten:
query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)Dies liest sich im Vergleich zu separaten Anweisungen fast wie natürliche Sprache. Methodenverkettung funktioniert am besten, wenn Operationen ein Objekt konfigurieren oder ändern, ohne andere Werte zurückgeben zu müssen. Sie wird häufig in Abfrage-Buildern, Konfigurations-APIs und Bibliotheken für Testassertionen verwendet.
Denke daran, dass jede Methode einen Pointer-Receiver verwenden und *StructType zurückgeben muss, damit die Verkettung ordnungsgemäß funktioniert.
Aufgabe
EinfachLass uns einen flüssigen HTML-Element-Builder erstellen, der Methodenverkettung verwendet, um HTML-Tags mit Attributen und Inhalt zu konstruieren! Dies ist eine praktische Anwendung der Methodenverkettung: Du erstellst eine API, die beim Erstellen von HTML-Elementen fast wie natürliche Sprache gelesen werden kann.
Du organisierst deinen Code über zwei Dateien:
element.go: Definiere deinen HTML-Element-Builder mit verkettbaren Methoden.Erstelle eine
Element-Struktur, die den Tagnamen, eine Attribut-Map (String zu String) und den inneren Inhalt speichert. Erstelle diese verkettbaren Methoden, die jeweils*Elementzurückgeben:NewElement(tag string)– Konstruktor, der ein neues Element mit dem angegebenen Tagnamen und einer initialisierten (leeren) Attribut-Map erstelltAttr(key, value string)– fügt dem Element ein Attribut hinzuID(id string)– Komfortmethode, die das Attribut „id“ setztClass(class string)– Komfortmethode, die das Attribut „class“ setztContent(text string)– setzt den inneren Inhalt des Elements
Füge eine
Render()-Methode hinzu, die den HTML-String zurückgibt. Attribute sollen alphabetisch nach Schlüssel sortiert erscheinen. Das Format ist:<tag attr1="value1" attr2="value2">content</tag>Wenn es keine Attribute gibt, rendere einfach
<tag>content</tag>. Wenn es keinen Inhalt gibt, rendere<tag attr="value"></tag>.main.go: Erstelle HTML-Elemente mithilfe der Methodenverkettung.Lies den Tagnamen ein und anschließend die Anzahl der auszuführenden Operationen. Jede Operation ist eine der folgenden:
id, gefolgt vom ID-Wertclass, gefolgt vom Klassenwertattr, gefolgt vom Attributnamen und -wert (zwei Zeilen)content, gefolgt vom Inhaltstext
Verknüpfe alle Operationen flüssig miteinander und gib anschließend das gerenderte HTML aus.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Tagname
- Zeile 2: Anzahl der Operationen
- Folgende Zeilen: Operationstyp und Wert(e)
Zum Beispiel bei folgender Eingabe:
div
3
id
container
class
main-content
content
Hello WorldDeine Ausgabe sollte folgendermaßen aussehen:
<div class="main-content" id="container">Hello World</div>Und bei folgender Eingabe:
a
3
attr
href
https://example.com
attr
target
_blank
content
Click hereDeine Ausgabe sollte folgendermaßen aussehen:
<a href="https://example.com" target="_blank">Click here</a>Und bei folgender Eingabe:
input
2
attr
type
text
attr
placeholder
Enter nameDeine Ausgabe sollte folgendermaßen aussehen:
<input placeholder="Enter name" type="text"></input>Und bei folgender Eingabe:
p
1
content
Simple paragraphDeine Ausgabe sollte folgendermaßen aussehen:
<p>Simple paragraph</p>Beachte, wie du mit der Methodenverkettung Elemente Schritt für Schritt auf lesbare Weise erstellen kannst. Jede Methode verändert das Element und gibt es zurück, sodass der nächste Methodenaufruf direkt angehängt werden kann.
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Tag-Namen lesen
scanner.Scan()
tagName := scanner.Text()
// Anzahl der Operationen lesen
scanner.Scan()
numOps, _ := strconv.Atoi(scanner.Text())
// Das Element erstellen
element := NewElement(tagName)
// Jede Operation verarbeiten
for i := 0; i < numOps; i++ {
scanner.Scan()
operation := scanner.Text()
// TODO: Basierend auf dem Operationstyp die entsprechende Methode verketten
// Operationen können sein: "id", "class", "attr" oder "content"
// - Für "id": die nächste Zeile als ID-Wert lesen
// - Für "class": die nächste Zeile als Klassenwert lesen
// - Für "attr": die nächsten ZWEI Zeilen lesen (Attributname, dann Wert)
// - Für "content": die nächste Zeile als Inhaltstext lesen
// Methodenverkettung verwenden, um das Element fließend aufzubauen
_ = operation // Diese Zeile beim Implementieren entfernen
}
// Gib das gerenderte HTML aus
fmt.Println(element.Render())
}
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 Pool12Fortgeschrittene OOP-Konzepte
Functional-Options-PatternBuilder-Pattern in GoMethod ChainingTyp-Aliase vs. DefinitionenGrundlagen der ReflectionÜberblick über CodegenerierungÜbe selbstständig: Online-Go-Compiler