Menu
Coddy logo textTech

Einbettung vs. Aggregation

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

Du hast gelernt, dass Einbettung Felder und Methoden in die äußere Struktur hebt. Go unterstützt jedoch auch Aggregation, bei der du eine andere Struktur als benanntes Feld einfügst. Zu verstehen, wann welcher Ansatz verwendet werden sollte, ist entscheidend für gutes Design.

Beim Embedding lässt du den Feldnamen weg, und die Mitglieder des inneren Typs werden direkt zugänglich:

type Writer struct{}
func (w Writer) Write() string { return "writing" }

type Document struct {
    Writer  // Einbettung – kein Feldname
}

d := Document{}
d.Write()  // direkter Zugriff

Bei der Aggregation gibst du dem Feld einen expliziten Namen, sodass dieser Name erforderlich ist, um auf den inneren Typ zuzugreifen:

type Document struct {
    writer Writer  // Aggregation - benanntes Feld
}

d := Document{writer: Writer{}}
d.writer.Write()  // muss den Feldnamen verwenden

Der entscheidende Unterschied ist die Beziehung, die du ausdrückst. Einbetten deutet auf eine „ist-ein“-Beziehung hin, bei der der äußere Typ die Identität des inneren Typs annimmt. Aggregation deutet auf eine „hat-ein“-Beziehung hin, bei der der äußere Typ den inneren Typ lediglich enthält.

Verwende Embedding, wenn der äußere Typ die von einem inneren Typ implementierten Schnittstellen erfüllen soll oder wenn der direkte Methodenzugriff die API übersichtlicher macht. Verwende Aggregation, wenn der innere Typ ein Implementierungsdetail ist, das nicht offengelegt werden sollte, oder wenn du ausdrücklich kontrollieren möchtest, wie auf den inneren Typ zugegriffen wird.

challenge icon

Aufgabe

Einfach

Erstellen wir ein System zur Berichtserstellung, das veranschaulicht, wann Einbettung statt Aggregation verwendet werden sollte. Du erstellst ein System, bei dem einige Komponenten direkt zugänglich sein sollten (Einbettung), während andere interne Implementierungsdetails bleiben sollten (Aggregation).

Du organisierst deinen Code über drei Dateien:

  • formatter.go: Erstelle eine Formatter-Struktur mit einem Style-Feld (String) und einer Format(text string) string-Methode, die den Text mit dem Stil umschlossen zurückgibt, wie [Style] text [/Style]. Dies ist eine interne Hilfskomponente, die nicht direkt offengelegt werden sollte.
  • report.go: Erstelle zwei Strukturen, die die Berichtserstellung unterschiedlich handhaben:
    • Eine Metadata-Struktur mit den Feldern Author und Date. Sie stellt öffentliche Informationen dar, die direkt zugänglich sein sollten
    • Eine Report-Struktur mit einem Title-Feld, die Metadata einbettet (für den direkten Zugriff auf Autor und Datum), aber für Formatter Aggregation verwendet (als internes Implementierungsdetail mit einem benannten Feld formatter)
    Füge der Generate() string-Struktur eine Report-Methode hinzu, die den internen Formatter verwendet, um den Titel zu formatieren, und die Metadaten einschließt.
  • main.go: Lies die Berichtsdaten aus der Eingabe, erstelle einen Report mit sowohl eingebetteten Metadaten als auch einem aggregierten Formatter. Veranschauliche den Unterschied, indem du direkt über den Report auf den Autor zugreifst (durch Einbettung) und anschließend den formatierten Bericht erzeugst (der intern den verborgenen Formatter verwendet).

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Berichtstitel
  • Zeile 2: Name des Autors
  • Zeile 3: Datum
  • Zeile 4: Formatter-Stil

Deine Format-Methode sollte Folgendes zurückgeben:

[Style] text [/Style]

Deine Generate-Methode sollte Folgendes zurückgeben:

[formatted title]
Author: [Author], Date: [Date]

Gib in deiner Hauptdatei drei Zeilen aus:

  1. Den direkt über den Report abgerufenen Autor (um zu zeigen, dass die Einbettung das Feld verfügbar macht)
  2. Das über den Namen des eingebetteten Typs abgerufene Datum (report.Metadata.Date)
  3. Das Ergebnis des Aufrufs von Generate()

Beispielsweise sollte deine Ausgabe bei Quarterly Results, Jane Doe, 2024-01-15 und BOLD folgendermaßen aussehen:

Jane Doe
2024-01-15
[BOLD] Quarterly Results [/BOLD]
Author: Jane Doe, Date: 2024-01-15

Beachte, wie Author und Date durch die Einbettung direkt über den Report zugänglich sind, während der Formatter verborgen bleibt. Du kannst report.Format() nicht direkt aufrufen, da er mit einem benannten Feld aggregiert wurde. Dies veranschaulicht den Unterschied zwischen der „ist-ein“- und der „hat-ein“-Beziehung in der Praxis.

Probier es selbst

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	scanner.Scan()
	title := scanner.Text()
	
	scanner.Scan()
	author := scanner.Text()
	
	scanner.Scan()
	date := scanner.Text()
	
	scanner.Scan()
	style := scanner.Text()
	
	// TODO: Erstelle eine Metadata-Struct mit dem Autor und dem Datum
	
	// TODO: Erstelle einen Formatter mit dem gegebenen Style
	
	// TODO: Erstelle einen Report, der Metadata einbettet und Formatter aggregiert
	
	// TODO: Gib den Autor aus, der direkt über den Report zugänglich ist (Einbettung promoted das Feld)
	
	// TODO: Gib das Datum aus, das über den eingebetteten Typnamen zugänglich ist (report.Metadata.Date)
	
	// TODO: Gib das Ergebnis des Aufrufs von Generate() aus
	
	// Unterdrücke Warnungen zu ungenutzten Variablen (entferne diese, wenn du die Variablen verwendest)
	_ = title
	_ = author
	_ = date
	_ = style
}
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