Menu
Coddy logo textTech

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, was es Ihnen ermöglicht, Instanzen zu erstellen, ohne die Erstellungslogik offenzulegen. Im Gegensatz zum Singleton, das die Anzahl der Instanzen kontrolliert, konzentriert sich Factory auf die flexible Objekterstellung basierend auf Eingabeparametern.

In Go ist eine Factory typischerweise eine Funktion, die einen Interface-Typ zurückgibt, wodurch Sie verschiedene konkrete Typen über eine einheitliche API erstellen können:

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 Factory-Funktion NewNotifier kapselt die Entscheidung, welcher konkrete Typ erstellt werden soll. Der Client-Code arbeitet nur mit dem Notifier-Interface und bleibt von der spezifischen Implementierung unbeeinflusst:

notifier := NewNotifier("sms")
result := notifier.Send("Hello!")  // "SMS: Hello!"

Dieses Muster glänzt, wenn Sie Objekte basierend auf Laufzeitbedingungen erstellen müssen, komplexe Initialisierungslogik zentralisieren möchten oder einfach neue Typen hinzufügen müssen, ohne den Client-Code zu ändern. Fügen Sie einfach ein neues Struct hinzu, das das Interface implementiert, und aktualisieren Sie die Factory-Funktion.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Dokumentenkonverter-System mit dem Factory-Muster erstellen! Sie werden eine Factory erstellen, die verschiedene Dokumentenkonverter basierend auf dem Zielformat erzeugt, sodass der Client-Code über eine einheitliche Schnittstelle mit jedem Konverter arbeiten kann.

Sie werden Ihren Code auf zwei Dateien aufteilen:

  • converter.go: Definieren Sie Ihr Konverter-Interface und die konkreten Implementierungen.

    Erstellen Sie ein Converter-Interface mit einer Methode Convert(content string) string, die den Dokumenteninhalt entgegennimmt und das konvertierte Ergebnis zurückgibt.

    Implementieren Sie drei Konverter-Typen:

    • PDFConverter — seine Convert-Methode gibt "PDF: " + content zurück
    • HTMLConverter — seine Convert-Methode gibt "HTML: <p>" + content + "</p>" zurück
    • MarkdownConverter — seine Convert-Methode gibt "MD: # " + content zurück

    Erstellen Sie eine Factory-Funktion NewConverter(format string) Converter, die basierend auf dem Format-String ("pdf", "html" oder "markdown") den entsprechenden Konverter zurückgibt. Für jedes nicht erkannte Format geben Sie standardmäßig einen PDFConverter zurück.

  • main.go: Verwenden Sie Ihre Factory, um Konverter zu erstellen und Dokumente zu verarbeiten.

    Lesen Sie einen Formattyp und den Dokumenteninhalt ein. Verwenden Sie die Factory, um den entsprechenden Konverter zu erstellen, konvertieren Sie dann den Inhalt und geben Sie das Ergebnis aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Formattyp ("pdf", "html", "markdown" oder etwas anderes)
  • Zeile 2: Zu konvertierender Dokumenteninhalt

Zum Beispiel, gegeben:

html
Welcome to Go Programming

Sollte Ihre Ausgabe wie folgt aussehen:

HTML: <p>Welcome to Go Programming</p>

Und gegeben:

markdown
Chapter One

Sollte Ihre Ausgabe wie folgt aussehen:

MD: # Chapter One

Und gegeben:

pdf
Annual Report 2024

Sollte Ihre Ausgabe wie folgt aussehen:

PDF: Annual Report 2024

Und gegeben:

docx
Meeting Notes

Sollte Ihre Ausgabe wie folgt aussehen:

PDF: Meeting Notes

Beachten Sie, dass der Hauptcode nichts über spezifische Konverter-Typen wissen muss — er fragt einfach die Factory nach einem Konverter und verwendet das Interface. Dies macht es einfach, später neue Formate hinzuzufügen, ohne den Client-Code zu ändern!

Spickzettel

Das Factory-Pattern (Fabrikmuster) delegiert die Objekterstellung an eine separate Funktion, was es ermöglicht, Instanzen zu erstellen, ohne die Erstellungslogik offenzulegen. Es konzentriert sich auf die flexible Objekterstellung basierend auf Eingabeparametern.

Eine Factory-Funktion gibt einen Interface-Typ zurück, was die Erstellung verschiedener konkreter Typen über eine einheitliche API ermöglicht:

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{}
    }
}

Der Client-Code arbeitet nur mit dem Interface und bleibt von den spezifischen Implementierungen unberührt:

notifier := NewNotifier("sms")
result := notifier.Send("Hello!")  // "SMS: Hello!"

Dieses Muster ist nützlich, wenn Sie Objekte basierend auf Laufzeitbedingungen erstellen müssen, komplexe Initialisierungslogik zentralisieren möchten oder neue Typen hinzufügen müssen, ohne den Client-Code 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: Die Factory verwenden, um den passenden Konverter zu erstellen
	// TODO: Den Inhalt konvertieren und das Ergebnis ausgeben
	
	fmt.Println(result)
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung