Menu
Coddy logo textTech

Einführung in Entwurfsmuster

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 85 von 107.

Entwurfsmuster sind wiederverwendbare Lösungen für häufig auftretende Probleme im Softwaredesign. Sie sind kein Code, den man direkt kopiert, sondern vielmehr Vorlagen, die anleiten, wie man seine Typen und deren Interaktionen strukturiert, um spezifische Herausforderungen zu lösen.

Design Patterns werden typischerweise in drei Kategorien unterteilt:

KategorieZweckBeispiele
ErzeugungsmusterMechanismen zur ObjekterzeugungSingleton, Factory, Builder
StrukturmusterZusammensetzen von Typen zu größeren StrukturenAdapter, Decorator, Composite
VerhaltensmusterKommunikation zwischen ObjektenObserver, Strategy, Command

In Go sehen Entwurfsmuster anders aus als in traditionellen OOP-Sprachen.

Ohne Klassen oder Vererbung implementiert Go Muster mittels Interfaces, Struct-Embedding und Komposition. Zum Beispiel verwendet Go ein Interface, wo Java eine abstrakte Klasse verwenden würde. Wo C++ Vererbung nutzen würde, nutzt Go Embedding.

Das Erlernen von Patterns hilft Ihnen dabei, häufige Probleme zu erkennen und Lösungen effektiv mit anderen Entwicklern zu kommunizieren. Wenn jemand erwähnt: „Verwenden Sie hier das Strategy-Pattern“, versteht das gesamte Team den Ansatz ohne langwierige Erklärungen.

In den nächsten Lektionen werden Sie mehrere grundlegende Muster in Go implementieren, beginnend mit Erzeugungsmustern wie Singleton und Factory, gefolgt von Verhaltensmustern wie Observer und Strategy.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein einfaches Benachrichtigungssystem bauen, das zeigt, wie Entwurfsmuster helfen, Code zu organisieren! Sie werden eine Struktur erstellen, die in zukünftigen Lektionen leicht mit Mustern wie Observer oder Strategy erweitert werden könnte – aber konzentrieren Sie sich vorerst darauf, saubere Schnittstellen und Typen einzurichten, die guten OOP-Prinzipien folgen.

Sie werden Ihren Code in drei Dateien organisieren:

  • notifier.go: Definieren Sie das Kern-Interface und die Typen für Ihr Benachrichtigungssystem.

    Erstellen Sie ein Notifier-Interface mit einer einzigen Methode Send(message string) string, die eine Bestätigungsnachricht zurückgibt.

    Implementieren Sie zwei konkrete Benachrichtigungstypen:

    • EmailNotifier mit einem Address-Feld – seine Send-Methode gibt Email to [address]: [message] zurück
    • SMSNotifier mit einem PhoneNumber-Feld – seine Send-Methode gibt SMS to [phone]: [message] zurück
  • dispatcher.go: Erstellen Sie einen Dispatcher, der über das Interface mit jedem Notifier zusammenarbeitet.

    Erstellen Sie ein NotificationDispatcher-Struct, das ein Slice von Notifier-Interfaces hält. Fügen Sie diese Methoden hinzu:

    • AddNotifier(n Notifier), um einen Notifier zu registrieren
    • Broadcast(message string) []string, das die Nachricht über alle registrierten Notifier sendet und ein Slice aller Bestätigungs-Strings zurückgibt

    Erstellen Sie außerdem einen NewNotificationDispatcher()-Konstruktor, der einen initialisierten Dispatcher zurückgibt.

  • main.go: Richten Sie Notifier ein und senden Sie Nachrichten per Broadcast.

    Lesen Sie die Anzahl der zu erstellenden Notifier ein. Lesen Sie für jeden Notifier seinen Typ (email oder sms) und sein Ziel (Adresse oder Telefonnummer) ein. Fügen Sie jeden einem Dispatcher hinzu.

    Lesen Sie dann eine Nachricht für den Broadcast ein. Senden Sie diese über alle Notifier und geben Sie jede Bestätigung in einer eigenen Zeile aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Anzahl der Notifier
  • Für jeden Notifier: Typ (email oder sms), dann das Ziel
  • Letzte Zeile: Nachricht für den Broadcast

Zum Beispiel, gegeben:

3
email
alice@example.com
sms
555-1234
email
bob@example.com
Server maintenance at midnight

Ihre Ausgabe sollte sein:

Email to alice@example.com: Server maintenance at midnight
SMS to 555-1234: Server maintenance at midnight
Email to bob@example.com: Server maintenance at midnight

Und gegeben:

2
sms
555-9999
sms
555-0000
Meeting canceled

Ihre Ausgabe sollte sein:

SMS to 555-9999: Meeting canceled
SMS to 555-0000: Meeting canceled

Diese Struktur zeigt, wie Interfaces flexible und erweiterbare Designs ermöglichen. Der Dispatcher kennt keine spezifischen Notifier-Typen – er weiß nur, dass sie Send ausführen können. Dies ist die Grundlage, auf der Muster wie Observer und Strategy aufbauen!

Spickzettel

Design-Patterns sind wiederverwendbare Lösungen für häufig auftretende Probleme im Softwaredesign. Sie sind Vorlagen, die vorgeben, wie Typen und deren Interaktionen strukturiert werden sollen.

Design-Patterns werden in drei Kategorien unterteilt:

KategorieZweckBeispiele
ErzeugungsmusterMechanismen zur ObjekterzeugungSingleton, Factory, Builder
StrukturmusterZusammensetzen von Typen zu größeren StrukturenAdapter, Decorator, Composite
VerhaltensmusterKommunikation zwischen ObjektenObserver, Strategy, Command

In Go werden Design-Patterns mithilfe von Interfaces, Struct-Embedding und Komposition anstelle von Klassen und Vererbung implementiert. Wo traditionelle OOP-Sprachen abstrakte Klassen verwenden, nutzt Go Interfaces. Wo diese Vererbung einsetzen, verwendet Go Embedding.

Probier es selbst

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Lies die Anzahl der Benachrichtiger
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	// Erstelle einen neuen Dispatcher
	dispatcher := NewNotificationDispatcher()

	// Lies jeden Benachrichtiger und füge ihn dem Dispatcher hinzu
	for i := 0; i < count; i++ {
		notifierType, _ := reader.ReadString('\n')
		notifierType = strings.TrimSpace(notifierType)

		destination, _ := reader.ReadString('\n')
		destination = strings.TrimSpace(destination)

		// TODO: Erstelle den entsprechenden Benachrichtiger basierend auf dem Typ
		// und füge ihn dem Dispatcher hinzu
		// Hinweis: Überprüfe, ob notifierType "email" oder "sms" ist

	}

	// Lies die zu sendende Nachricht
	message, _ := reader.ReadString('\n')
	message = strings.TrimSpace(message)

	// TODO: Sende die Nachricht an alle und gib jede Bestätigung aus

}
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