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 Unexportiert-Machen 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 völlig anderes sein. Die Implementierung kann sich ändern, ohne den 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 nicht exportiert:

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

// nicht exportiert - interne Hilfsfunktion
func (c *Counter) isAtLimit() bool {
    return c.value >= c.maxLimit
}

Indem Sie isAtLimit() verbergen, können Sie es später frei ändern oder entfernen. Information Hiding schafft eine klare Trennung 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 demonstriert. Sie werden ein digitales Wallet erstellen, bei dem die interne Kontostandsverfolgung und der Transaktionsverlauf 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 - entfernt Geld, 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, erstellen Sie ein Wallet, führen Sie Operationen durch 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 ursprünglichen Status aus. Führen Sie dann jede Operation aus und geben Sie entweder den aktualisierten Status (bei Erfolg) oder Transaction failed (wenn 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.

Spickzettel

Information Hiding bedeutet, Typen so zu entwerfen, dass externer Code nur das erfährt, was er wissen muss. Exponieren Sie Verhalten durch Methoden, während die interne Struktur vollständig verborgen bleibt.

Beispiel für einen Typ mit verborgener Implementierung:

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 kennt die interne Repräsentation nicht (es könnte int, float64 oder etwas anderes sein). Die Implementierung kann sich ändern, ohne den Code zu beeinflussen, der sie verwendet.

Halten Sie Hilfsfunktionen unexportiert:

// Exported - part of public API
func (c *Counter) Reset() {
    c.value = 0
}

// unexported - internal helper
func (c *Counter) isAtLimit() bool {
    return c.value >= c.maxLimit
}

Information Hiding schafft eine klare Grenze zwischen dem, was Ihr Paket nach außen verspricht, und wie es intern funktioniert.

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 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