Factory-Muster
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 87 von 107.
Das Factory pattern delegiert die Objekterstellung an eine separate Funktion oder Methode und ermöglicht es dir, Instanzen zu erstellen, ohne die Erstellungslogik offenzulegen. Im Gegensatz zum Singleton, das die Anzahl der Instanzen steuert, konzentriert sich die Factory auf die flexible Objekterstellung anhand von Eingabeparametern.
In Go ist eine Factory typischerweise eine Funktion, die einen Schnittstellentyp zurückgibt und es dir ermöglicht, verschiedene konkrete Typen über eine einheitliche API zu erstellen:
type Notifier interface {
Send(message string) string
}
type EmailNotifier struct{}
type SMSNotifier struct{}
func (e EmailNotifier) Send(message string) string {
return "Email: " + message
}
func (s SMSNotifier) Send(message string) string {
return "SMS: " + message
}
func NewNotifier(notifierType string) Notifier {
switch notifierType {
case "email":
return EmailNotifier{}
case "sms":
return SMSNotifier{}
default:
return EmailNotifier{}
}
}Die Fabrikfunktion NewNotifier kapselt die Entscheidung darüber, welchen konkreten Typ erstellt werden soll. Der Client-Code arbeitet nur mit dem Notifier-Interface und bleibt von der spezifischen Implementierung unberührt:
notifier := NewNotifier("sms")
result := notifier.Send("Hello!") // "SMS: Hello!"Dieses Muster ist besonders nützlich, wenn du Objekte basierend auf Laufzeitbedingungen erstellen musst, komplexe Initialisierungslogik zentralisieren möchtest oder problemlos neue Typen hinzufügen musst, ohne den Client-Code zu ändern. Füge einfach eine neue Struktur hinzu, die das Interface implementiert, und aktualisiere die Factory-Funktion.
Aufgabe
EinfachLass uns ein Dokumentkonvertersystem mithilfe des Fabrikmusters erstellen! Du wirst eine Fabrik erstellen, die abhängig vom Zielformat verschiedene Dokumentkonverter erzeugt, sodass der Clientcode über eine einheitliche Schnittstelle mit jedem Konverter arbeiten kann.
Du wirst deinen Code auf zwei Dateien aufteilen:
converter.go: Definiere deine Konverterschnittstelle und konkrete Implementierungen.Erstelle eine
Converter-Schnittstelle mit einer MethodeConvert(content string) string, die den Dokumentinhalt übernimmt und die konvertierte Ausgabe zurückgibt.Implementiere drei Konvertertypen:
PDFConverter: Die MethodeConvertgibtPDF: [content]zurückHTMLConverter: Die MethodeConvertgibtHTML: <p>[content]</p>zurückMarkdownConverter: Die MethodeConvertgibtMD: # [content]zurück
Erstelle eine Fabrikfunktion
NewConverter(format string) Converter, die abhängig vom Format-String (pdf,htmlodermarkdown) den passenden Konverter zurückgibt. Gib für jedes nicht erkannte Format standardmäßig einenPDFConverterzurück.main.go: Verwende deine Fabrik, um Konverter zu erstellen und Dokumente zu verarbeiten.Lies einen Formattyp und den Dokumentinhalt ein. Verwende die Fabrik, um den passenden Konverter zu erstellen, konvertiere anschließend den Inhalt und gib das Ergebnis aus.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Formattyp (
pdf,html,markdownoder etwas anderes) - Zeile 2: Zu konvertierender Dokumentinhalt
Zum Beispiel bei:
html
Welcome to Go ProgrammingDeine Ausgabe sollte sein:
HTML: <p>Welcome to Go Programming</p>Und bei:
markdown
Chapter OneDeine Ausgabe sollte sein:
MD: # Chapter OneUnd bei:
pdf
Annual Report 2024Deine Ausgabe sollte sein:
PDF: Annual Report 2024Und bei:
docx
Meeting NotesDeine Ausgabe sollte sein:
PDF: Meeting NotesBeachte, dass der Hauptcode die spezifischen Konvertertypen nicht kennen muss. Er fordert einfach einen Konverter von der Fabrik an und verwendet die Schnittstelle. Dadurch lassen sich später problemlos neue Formate hinzufügen, ohne den Clientcode zu ändern!
Probier es selbst
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Formattyp lesen
scanner.Scan()
format := scanner.Text()
// Dokumentinhalt lesen
scanner.Scan()
content := scanner.Text()
// TODO: Verwende die Factory, um den entsprechenden Converter zu erstellen
// TODO: Konvertiere den Inhalt und gib das Ergebnis aus
fmt.Println(result)
}
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 Sammlung13Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterAbstraktes Factory-MusterObserver-MusterStrategy-Muster2Typen & 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