Menu
Coddy logo textTech

Implizite Implementierung

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

In vielen objektorientierten Sprachen wie Java oder C# musst du ausdrücklich deklarieren, dass ein Typ ein Interface mithilfe von Schlüsselwörtern wie implements implementiert. Go verfolgt einen anderen Ansatz: Die Implementierung von Interfaces erfolgt implizit.

Ein Typ erfüllt eine Schnittstelle einfach dadurch, dass er alle ihre Methoden implementiert. Es ist nicht erforderlich, die Beziehung irgendwo zu deklarieren. Der Compiler erkennt sie automatisch.

type Writer interface {
    Write(data string) int
}

type FileWriter struct {
    Filename string
}

// FileWriter implementiert Writer implizit
func (f FileWriter) Write(data string) int {
    fmt.Println("Writing to", f.Filename)
    return len(data)
}

Beachte, dass es keine implements Writer-Deklaration bei FileWriter gibt. Da FileWriter über eine Write(data string) int-Methode verfügt, die mit der Signatur der Schnittstelle übereinstimmt, erfüllt es automatisch die Writer-Schnittstelle.

Dieses Design hat eine wichtige Konsequenz: Du kannst Schnittstellen definieren, nachdem Typen bereits existieren. Wenn eine Bibliothek eines Drittanbieters einen Typ mit den benötigten Methoden enthält, kannst du eine Schnittstelle erstellen, die dieser bereits erfüllt, ohne den ursprünglichen Code zu ändern.

func Save(w Writer, content string) {
    w.Write(content)
}

func main() {
    fw := FileWriter{Filename: "data.txt"}
    Save(fw, "Hello!")  // Funktioniert, weil FileWriter Writer erfüllt
}

Die implizite Implementierung hält Go-Code entkoppelt und flexibel. Typen müssen Schnittstellen nicht im Voraus kennen, wodurch es einfacher wird, Systeme aus unabhängigen Teilen zusammenzusetzen.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Nachrichtenübermittlungssystem, das veranschaulicht, wie Typen in Go implizit Schnittstellen erfüllen. Du erstellst verschiedene Nachrichtentypen, die alle dieselbe Schnittstelle erfüllen, ohne diese Beziehung jemals explizit zu deklarieren.

Du organisierst deinen Code auf zwei Dateien:

  • messengers.go: Definiere eine Messenger-Schnittstelle mit einer einzigen Methode Send(message string) string. Erstelle dann zwei Strukturen, die diese Schnittstelle implizit erfüllen:
    • EmailMessenger mit einem Address-Feld (String)
    • SMSMessenger mit einem PhoneNumber-Feld (String)
    Jede Struktur sollte eine Send-Methode besitzen, die einen String zurückgibt, der die Übermittlung beschreibt. Keine der beiden Strukturen sollte explizit deklarieren, dass sie Messenger implementiert: Go erkennt das automatisch anhand der Methodensignaturen.
  • main.go: Erstelle eine Funktion namens DeliverMessage, die einen beliebigen Messenger und einen Nachrichten-String akzeptiert und anschließend das Ergebnis des Aufrufs von Send zurückgibt. Lies Kontaktinformationen aus der Eingabe, erstelle beide Nachrichtentypen und verwende deine Funktion, um über jeden von ihnen Nachrichten zu übermitteln.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: E-Mail-Adresse
  • Zeile 2: Telefonnummer
  • Zeile 3: Zu sendende Nachricht

Deine Send-Methoden sollten Strings in diesen Formaten zurückgeben:

  • EmailMessenger: Email to [Address]: [message]
  • SMSMessenger: SMS to [PhoneNumber]: [message]

Wenn beispielsweise alice@example.com, 555-1234 und Hello! gegeben sind, sollte deine Ausgabe folgendermaßen aussehen:

Email to alice@example.com: Hello!
SMS to 555-1234: Hello!

Die wichtigste Erkenntnis ist hier, dass deine DeliverMessage-Funktion jeden beliebigen Messenger akzeptiert und sowohl EmailMessenger als auch SMSMessenger diese Schnittstelle allein dadurch erfüllen, dass sie über eine passende Send-Methode verfügen. Es gibt nirgendwo ein implements-Schlüsselwort: Gos implizite Implementierung erledigt all das automatisch.

Probier es selbst

package main

import (
	"bufio"
	"fmt"
	"os"
)

// TODO: Erstelle eine DeliverMessage-Funktion, die einen beliebigen Messenger akzeptiert
// und einen message-String, und dann das Ergebnis des Aufrufs von Send zurückgibt

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Read email address
	email, _ := reader.ReadString('\n')
	email = email[:len(email)-1]
	
	// Telefonnummer lesen
	phone, _ := reader.ReadString('\n')
	phone = phone[:len(phone)-1]
	
	// Nachricht lesen
	message, _ := reader.ReadString('\n')
	if len(message) > 0 && message[len(message)-1] == '\n' {
		message = message[:len(message)-1]
	}
	
	// TODO: Erstelle einen EmailMessenger mit der E-Mail-Adresse
	
	// TODO: Erstelle einen SMSMessenger mit der Telefonnummer
	
	// TODO: Verwende DeliverMessage, um die Nachricht über jeden Messenger zu senden
	// und gib die Ergebnisse 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

Übe selbstständig: Online-Go-Compiler