Menu
Coddy logo textTech

Informationsverbergung in Go

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

Informationsverbergen geht über das bloße Ausblenden von Feldern hinaus. Es geht darum, deine Typen so zu entwerfen, dass externer Code nur weiß, was er wissen muss. Nicht mehr.

Das Ziel besteht darin, Verhalten über Methoden offenzulegen und dabei die interne Struktur vollständig verborgen zu halten. Betrachte diesen Ansatz:

type Counter struct {
    value    int
    maxLimit int
}

func NewCounter(limit int) *Counter {
    return &Counter{maxLimit: limit}
}

func (c *Counter) Increment() bool {
    if c.value >= c.maxLimit {
        return false
    }
    c.value++
    return true
}

func (c *Counter) Value() int {
    return c.value
}

Externer Code weiß nicht, dass Counter intern ein int verwendet. Es könnte ein float64, ein Slice oder etwas völlig anderes sein. Die Implementierung kann geändert werden, ohne dass irgendein Code betroffen ist, der Counter verwendet, solange sich die Methoden gleich verhalten.

Dieses Prinzip gilt auch für Hilfsfunktionen. Halte die interne Logik nicht exportiert:

// Exportiert - Teil der öffentlichen API
func (c *Counter) Reset() {
    c.value = 0
}

// unexportiert - interner Helfer
func (c *Counter) isAtLimit() bool {
    return c.value >= c.maxLimit
}

Indem du isAtLimit() verbirgst, kannst du es später problemlos ändern oder entfernen. Informationsverbergung schafft eine klare Grenze zwischen dem, was dein Paket externen Nutzern verspricht, und der internen Funktionsweise.

challenge icon

Aufgabe

Einfach

Lass uns ein sicheres Wallet-System entwickeln, das Informationsverbergung demonstriert. Du erstellst ein digitales Wallet, bei dem die interne Verwaltung des Guthabens und der Transaktionsverlauf vollständig vor externem Code verborgen sind: Über Methoden wird nur das Verhalten offengelegt.

Du organisierst deinen Code über zwei Dateien:

  • wallet.go: Erstelle eine Wallet-Struktur, die ihren gesamten internen Zustand verbirgt. Das Wallet soll das aktuelle Guthaben und ein Ausgabenlimit intern verwalten, aber externer Code soll niemals wissen, wie diese gespeichert oder dargestellt werden. Lege das Verhalten über diese Methoden offen:
    • NewWallet(limit float64) *Wallet – Konstruktor, der ein Wallet mit dem angegebenen Ausgabenlimit und einem Guthaben von null erstellt
    • Deposit(amount float64) bool – fügt dem Wallet Geld hinzu und gibt true zurück, wenn der Vorgang erfolgreich war (der Betrag muss positiv sein)
    • Spend(amount float64) bool – entfernt Geld, wenn ein ausreichendes Guthaben vorhanden ist UND der Betrag das Ausgabenlimit nicht überschreitet, und gibt true zurück, wenn der Vorgang erfolgreich war
    • Balance() float64 – gibt das aktuelle Guthaben zurück
    • Status() string – gibt eine Statusmeldung im Format Balance: $[balance] (Limit: $[limit]) zurück
    Bewahre jegliche Hilfslogik (z. B. die Überprüfung, ob eine Transaktion gültig ist) als nicht exportierte Funktionen oder Methoden auf. Dabei handelt es sich um interne Implementierungsdetails, die sich später ändern könnten.
  • main.go: Lies die Wallet-Konfiguration und die Transaktionen aus der Eingabe, erstelle ein Wallet, führe die Vorgänge aus und zeige nach jeder Aktion die Ergebnisse an.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Ausgabenlimit
  • Zeile 2: Einzahlungsbetrag
  • Zeile 3: Erster Ausgabebetrag
  • Zeile 4: Zweiter Ausgabebetrag

Gib nach dem Erstellen des Wallets zunächst dessen Status aus. Führe dann jeden Vorgang aus und gib entweder den aktualisierten Status (wenn der Vorgang erfolgreich war) oder Transaction failed (wenn der Vorgang abgelehnt wurde) aus. Formatiere alle Dollarbeträge mit zwei Nachkommastellen.

Wenn beispielsweise 50, 100, 30 und 80 angegeben werden, sollte deine Ausgabe folgendermaßen aussehen:

Balance: $0.00 (Limit: $50.00)
Balance: $100.00 (Limit: $50.00)
Balance: $70.00 (Limit: $50.00)
Transaction failed

Die letzte Transaktion schlägt fehl, weil $80 das Ausgabenlimit von $50 überschreitet, obwohl genügend Guthaben vorhanden ist. Das Wallet setzt seine Regeln intern durch, ohne offenzulegen, wie es diese Entscheidungen trifft. Externer Code ruft einfach Methoden auf und erhält Ergebnisse, ohne jemals die internen Implementierungsdetails zu kennen.

Probier es selbst

package main

import (
	"fmt"
)

func main() {
	// Eingaben lesen
	var limit float64
	var depositAmount float64
	var spend1 float64
	var spend2 float64

	fmt.Scanln(&limit)
	fmt.Scanln(&depositAmount)
	fmt.Scanln(&spend1)
	fmt.Scanln(&spend2)

	// TODO: Erstelle eine neue Wallet mit dem gegebenen Ausgabenlimit

	// TODO: Initialen Status ausgeben

	// TODO: Perform deposit and print result (status or "Transaction failed")

	// TODO: Erste Ausgabe durchführen und Ergebnis ausgeben

	// TODO: Zweite Ausgabe durchführen und Ergebnis ausgeben
}
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