Menu
Coddy logo textTech

Information Hiding in Go

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

Information Hiding geht über das bloße Nicht-Exportieren von Feldern hinaus. Es geht darum, Ihre Typen so zu entwerfen, dass externer Code nur das erfährt, was er wissen muss – nicht mehr.

Das Ziel ist es, Verhalten durch Methoden offenzulegen, während die interne Struktur vollständig verborgen bleibt. Betrachten Sie 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 ganz anderes sein. Die Implementierung kann sich ändern, ohne Code zu beeinflussen, der Counter verwendet – solange sich die Methoden auf die gleiche Weise verhalten.

Dieses Prinzip gilt auch für Hilfsfunktionen. Halten Sie die interne Logik unexportiert:

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

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

Indem Sie isAtLimit() verbergen, steht es Ihnen frei, dies später zu ändern oder zu entfernen. Das Verbergen von Informationen schafft eine klare Grenze zwischen dem, was Ihr Paket externen Benutzern verspricht, und wie es intern funktioniert.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein sicheres Wallet-System bauen, das Information Hiding (Datenkapselung) demonstriert. Sie werden ein digitales Wallet erstellen, bei dem die interne Kontostandsverfolgung und die Transaktionshistorie vollständig vor externem Code verborgen sind – nur das Verhalten wird über Methoden offengelegt.

Sie werden Ihren Code in zwei Dateien organisieren:

  • wallet.go: Erstellen Sie ein Wallet-Struct, das seinen gesamten internen Zustand verbirgt. Das Wallet sollte den aktuellen Kontostand und ein Ausgabenlimit intern verfolgen, aber externer Code sollte niemals wissen, wie diese gespeichert oder dargestellt werden. Legen Sie das Verhalten über diese Methoden offen:
    • NewWallet(limit float64) *Wallet - Konstruktor, der ein Wallet mit dem angegebenen Ausgabenlimit und einem Kontostand von Null erstellt
    • Deposit(amount float64) bool - fügt dem Wallet Geld hinzu, gibt true zurück, wenn erfolgreich (Betrag muss positiv sein)
    • Spend(amount float64) bool - hebt Geld ab, wenn ausreichend Guthaben vorhanden ist UND der Betrag das Ausgabenlimit nicht überschreitet, gibt true zurück, wenn erfolgreich
    • Balance() float64 - gibt den aktuellen Kontostand zurück
    • Status() string - gibt eine Statusmeldung im Format: Balance: $[balance] (Limit: $[limit]) zurück
    Halten Sie jegliche Hilfslogik (wie die Prüfung, ob eine Transaktion gültig ist) als nicht exportierte Funktionen oder Methoden – dies sind interne Implementierungsdetails, die sich später ändern könnten.
  • main.go: Lesen Sie die Wallet-Konfiguration und Transaktionen aus der Eingabe ein, erstellen Sie ein Wallet, führen Sie Operationen aus und zeigen Sie die Ergebnisse nach jeder Aktion an.

Die folgenden Eingaben werden bereitgestellt:

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

Geben Sie nach dem Erstellen des Wallets seinen Anfangsstatus aus. Führen Sie dann jede Operation aus und geben Sie entweder den aktualisierten Status (falls erfolgreich) oder Transaction failed (falls die Operation abgelehnt wurde) aus. Formatieren Sie alle Dollarbeträge mit zwei Dezimalstellen.

Zum Beispiel, gegeben 50, 100, 30 und 80, sollte Ihre Ausgabe wie folgt 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, da $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 angegebenen Ausgabenlimit

	// TODO: Initialen Status ausgeben

	// TODO: Einzahlung durchführen und Ergebnis ausgeben (Status oder "Transaction failed")

	// TODO: Erste Ausgabe tätigen und Ergebnis ausgeben

	// TODO: Zweite Ausgabe tätigen 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