Menu
Coddy logo textTech

Ukrywanie informacji

Część sekcji Programowanie obiektowe ścieżki Dart w Coddy. Lekcja 34 z 110.

Ukrywanie informacji to zasada leżąca u podstaw enkapsulacji — idea, że klasa powinna ukrywać swoje wewnętrzne działanie i udostępniać tylko to, co niezbędne. Poznałeś już mechanizmy (pola prywatne, metody pobierające i ustawiające), ale prawdziwym celem jest projektowanie klas, które są łatwe w użyciu i trudne do niewłaściwego użycia.

Rozważ klasę, która zarządza hasłem użytkownika. Wewnętrzne przechowywanie i logika haszowania powinny być całkowicie ukryte:

class UserAccount {
  String _username;
  String _passwordHash;
  
  UserAccount(this._username, String password) 
      : _passwordHash = _hashPassword(password);
  
  static String _hashPassword(String password) {
    return 'hashed_$password';  // Uproszczony przykład
  }
  
  bool verifyPassword(String password) {
    return _passwordHash == _hashPassword(password);
  }
  
  String get username => _username;
}

Zewnętrzny kod nigdy nie widzi skrótu hasła ani nie wie, jak jest on przechowywany. Po prostu wywołuje verifyPassword(). Dzięki temu rozdzieleniu możesz całkowicie zmienić algorytm haszowania bez wpływu na kod korzystający z tej klasy.

Kluczowa wskazówka: myśl o swojej klasie od zewnątrz do wewnątrz.

Zadaj sobie pytanie: „Czego tak naprawdę potrzebuje osoba korzystająca z tej klasy?”. Udostępniaj tylko to, a wszystko inne zachowaj jako prywatne. Dzięki temu powstaje wyraźna granica między tym, co robi twoja klasa (jej publicznym interfejsem), a tym, jak to robi (jej prywatną implementacją).

challenge icon

Wyzwanie

Łatwy

Zbudujmy bezpieczny system portfela, który pokazuje w praktyce ukrywanie informacji. Utworzysz cyfrowy portfel zarządzający saldem użytkownika i historią transakcji, przy czym wszystkie wrażliwe szczegóły wewnętrzne będą całkowicie ukryte przed kodem zewnętrznym.

Podzielisz kod na dwa pliki:

  • wallet.dart: Utwórz klasę Wallet, która bezpiecznie zarządza pieniędzmi. Portfel powinien publicznie przechowywać imię właściciela, ale wszystko inne powinno być ukryte za przejrzystym publicznym interfejsem:
    • Wewnętrzne saldo i rejestr transakcji powinny być prywatne — kod zewnętrzny nigdy nie powinien widzieć, jak przechowujesz pieniądze ani śledzisz transakcje
    • Prywatna metoda powinna wewnętrznie obsługiwać rejestrowanie transakcji (przechowując wpisy takie jak "Deposit: $50.0" lub "Withdrawal: $30.0")
    • Udostępnij publiczną metodę deposit(double amount), która dodaje pieniądze (tylko jeśli kwota jest dodatnia) i wewnętrznie rejestruje transakcję
    • Udostępnij publiczną metodę withdraw(double amount), która wypłaca pieniądze tylko wtedy, gdy dostępne środki są wystarczające, a kwota jest dodatnia, oraz wewnętrznie rejestruje transakcję. Zwróć true, jeśli operacja się powiedzie, w przeciwnym razie false
    • Udostępnij publiczny getter balance, który zwraca bieżące saldo (dostęp tylko do odczytu)
    • Udostępnij publiczną metodę getTransactionCount(), która zwraca liczbę zarejestrowanych transakcji (nie ujawniając rzeczywistej listy transakcji)
    • Udostępnij publiczną metodę getLastTransaction(), która zwraca tekst ostatniej transakcji lub "No transactions", jeśli nie ma żadnych transakcji
    • Dodaj metodę printSummary(), która wyświetla stan portfela
  • main.dart: Zaimportuj portfel i pokaż, jak ukrywanie informacji tworzy przejrzysty i bezpieczny interfejs:
    • Utwórz portfel dla właściciela "Sarah"
    • Wpłać 100.0
    • Wpłać 50.0
    • Spróbuj wypłacić 200.0 i wyświetl "Withdrawal of 200.0: [success/failed]" zależnie od wyniku
    • Wypłać 30.0 i wyświetl "Withdrawal of 30.0: [success/failed]"
    • Wywołaj printSummary()
    • Wyświetl "Transaction count: [count]"
    • Wyświetl "Last transaction: [transaction]"

Metoda printSummary() powinna wyświetlać:

=== Wallet Summary ===
Owner: [ownerName]
Balance: $[balance]

Zwróć uwagę, że kod zewnętrzny może komunikować się z portfelem za pomocą przejrzystych, celowych metod, nie wiedząc przy tym, jak przechowywane jest saldo ani jak wewnętrznie śledzone są transakcje. Szczegóły implementacji są całkowicie ukryte — możesz zmienić sposób przechowywania transakcji bez wpływu na kod korzystający z portfela.

Oczekiwany wynik:

Withdrawal of 200.0: failed
Withdrawal of 30.0: success
=== Wallet Summary ===
Owner: Sarah
Balance: $120.0
Transaction count: 3
Last transaction: Withdrawal: $30.0

Spróbuj swoich sił

import 'wallet.dart';

void main() {
  // TODO: Utwórz portfel dla właścicielki "Sarah"
  
  // TODO: Wpłać 100.0
  
  // TODO: Wpłać 50.0
  
  // TODO: Spróbuj wypłacić 200.0 i wyświetl wynik
  // Format: "Withdrawal of 200.0: [success/failed]"
  
  // TODO: Wypłać 30.0 i wyświetl wynik
  // Format: "Withdrawal of 30.0: [success/failed]"
  
  // TODO: Wywołaj printSummary()
  
  // TODO: Wyświetl liczbę transakcji
  // Format: "Transaction count: [count]"
  
  // TODO: Wyświetl ostatnią transakcję
  // Format: "Last transaction: [transaction]"
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Dart online