Menu
Coddy logo textTech

Implementacja ukrywania danych

Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 33 z 70.

Ukrywanie danych wykracza poza samo używanie pól private. Chodzi o zaprojektowanie klasy tak, aby szczegóły jej wewnętrznej implementacji były całkowicie niewidoczne dla kodu zewnętrznego, a przez przejrzysty interfejs publiczny udostępniała tylko to, co niezbędne.

Rozważ klasę, która śledzi hasło użytkownika. Nie chcesz, aby ktokolwiek miał dostęp do niezaszyfrowanego hasła — nawet po to, by je odczytać:

public class UserAccount
{
    private string passwordHash;
    
    public void SetPassword(string password)
    {
        passwordHash = HashPassword(password);
    }
    
    public bool VerifyPassword(string password)
    {
        return HashPassword(password) == passwordHash;
    }
    
    private string HashPassword(string password)
    {
        return password.GetHashCode().ToString();
    }
}

Zauważ, że nie ma sposobu na odzyskanie hasła ani nawet skrótu. Zewnętrzny kod może jedynie ustawić hasło lub je zweryfikować — wewnętrzny mechanizm przechowywania jest całkowicie ukryty. Metoda HashPassword jest również prywatna, ponieważ stanowi szczegół implementacji, który może ulec zmianie bez wpływu na sposób użycia klasy.

To podejście chroni Twoją klasę przed niewłaściwym użyciem i daje Ci swobodę późniejszej zmiany szczegółów implementacji. Jeśli zdecydujesz się użyć innego algorytmu haszującego, żaden zewnętrzny kod nie przestanie działać, ponieważ nic nie zależało od sposobu przechowywania hasła.

challenge icon

Wyzwanie

Łatwy

Zbudujmy bezpieczny system portfela, który pokazuje, na czym polega prawdziwe ukrywanie danych. Utworzysz portfel cyfrowy, którego saldo jest całkowicie chronione przed bezpośrednim dostępem — zewnętrzny kod może jedynie wpłacać środki, wypłacać je i sprawdzać, czy transakcje są możliwe, ale nigdy nie może bezpośrednio zobaczyć ani zmieniać właściwego salda.

Rozmieścisz swój kod w dwóch plikach:

  • Wallet.cs: Utwórz klasę Wallet w przestrzeni nazw Finance, która całkowicie ukrywa saldo. Portfel powinien mieć:
    • Pole prywatne do przechowywania salda (decimal)
    • Prywatną metodę FormatBalance(), która zwraca saldo sformatowane jako ciąg znaków reprezentujący walutę, na przykład "$123.45" — to wewnętrzna metoda pomocnicza, która nie powinna być udostępniana
    • Metodę publiczną Deposit(decimal amount), która dodaje środki do salda tylko wtedy, gdy kwota jest dodatnia, i zwraca true w przypadku powodzenia, a w przeciwnym razie false
    • Metodę publiczną Withdraw(decimal amount), która odejmuje środki od salda tylko wtedy, gdy kwota jest dodatnia i nie przekracza bieżącego salda, i zwraca true w przypadku powodzenia, a w przeciwnym razie false
    • Metodę publiczną CanAfford(decimal amount), która zwraca true, jeśli saldo jest większe lub równe podanej kwocie, a w przeciwnym razie false
    • Metodę publiczną GetStatement(), która wewnętrznie używa prywatnej metody FormatBalance() i zwraca "Current balance: {formatted balance}"
    Zauważ, że nie ma możliwości bezpośredniego odczytania ani ustawienia salda — możesz z nim wchodzić w interakcję tylko za pomocą kontrolowanych metod!
  • Program.cs: W pliku głównym utwórz obiekt Wallet i wykonaj serię transakcji, używając wartości wejściowych. Pokaż, jak portfel chroni swój stan wewnętrzny, a jednocześnie udostępnia przydatne funkcje za pośrednictwem publicznego interfejsu.

Otrzymasz trzy dane wejściowe:

  • Początkowa kwota wpłaty (decimal)
  • Kwota wypłaty, którą należy spróbować wypłacić (decimal)
  • Kwota, dla której należy sprawdzić dostępność środków (decimal)

Wyświetl wynik w tym formacie:

Deposit {amount}: {True/False}
{GetStatement() result}
Withdraw {amount}: {True/False}
{GetStatement() result}
Can afford {amount}: {True/False}

Na przykład, jeśli dane wejściowe to 100.50, 30.25 i 80.00, wynik powinien wyglądać następująco:

Deposit 100.50: True
Current balance: $100.50
Withdraw 30.25: True
Current balance: $70.25
Can afford 80.00: False

Najważniejsza myśl jest taka, że zewnętrzny kod nigdy nie uzyskuje bezpośredniego dostępu do pola salda. Nawet sformatowany ciąg znaków z saldem jest zwracany przez metodę publiczną, która wewnętrznie korzysta z prywatnej metody pomocniczej. To właśnie ukrywanie danych — szczegóły implementacji są całkowicie niewidoczne, a sposób przechowywania lub formatowania salda możesz zmienić bez naruszania kodu korzystającego z portfela!

Spróbuj swoich sił

using System;
using Finance;

class Program
{
    public static void Main(string[] args)
    {
        // Odczytaj wartości wejściowe
        decimal depositAmount = Convert.ToDecimal(Console.ReadLine());
        decimal withdrawAmount = Convert.ToDecimal(Console.ReadLine());
        decimal checkAmount = Convert.ToDecimal(Console.ReadLine());

        // TODO: Utwórz instancję Wallet
        
        // TODO: Wpłać środki i wypisz wynik w formacie: "Deposit {amount}: {True/False}"
        
        // TODO: Wypisz zestawienie za pomocą GetStatement()
        
        // TODO: Wypłać środki i wypisz wynik w formacie: "Withdraw {amount}: {True/False}"
        
        // TODO: Wypisz zestawienie za pomocą GetStatement()
        
        // TODO: Sprawdź, czy wystarczy środków, i wypisz wynik w formacie: "Can afford {amount}: {True/False}"
    }
}
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 C# online