Menu
Coddy logo textTech

System bankowy

Część sekcji Programowanie obiektowe ścieżki Java w Coddy. Lekcja 85 z 87.

To wyzwanie polega na zbudowaniu systemu bankowego, który modeluje rzeczywiste operacje finansowe z wykorzystaniem zasad programowania obiektowego.

Twój system powinien obsługiwać różne typy kont, takie jak SavingsAccount i CheckingAccount, które rozszerzają bazową klasę Account. Każdy typ konta ma unikalne zachowania: konta oszczędnościowe mogą przynosić odsetki, a konta rozliczeniowe mogą zapewniać ochronę przed debetem.

Zastanów się, jak modelować transakcje. Interfejs taki jak Transactable mógłby definiować metody deposit() i withdraw(). Rozważ użycie własnych wyjątków, takich jak InsufficientFundsException, aby poprawnie obsługiwać nieprawidłowe operacje.

Klasa Bank może zarządzać wieloma kontami i klientami, demonstrując kompozycję. Możesz zastosować wzorzec Factory do tworzenia różnych typów kont lub użyć wzorca Observer, aby powiadamiać klientów o zmianach na kontach.

Skup się na enkapsulacji, aby chronić wrażliwe dane, takie jak salda i numery kont, oraz używaj polimorfizmu do jednolitego przetwarzania różnych typów kont.

challenge icon

Wyzwanie

Łatwy

Zbudujmy kompletny system bankowy, który pokaże, jak dobrze opanowałeś zasady OOP! Stworzysz system z różnymi typami kont, obsługą transakcji i prawidłowym zarządzaniem wyjątkami — wszystko uporządkowane w wielu plikach.

Uporządkujesz kod w siedmiu plikach:

  • Transactable.java: Utwórz interfejs definiujący kontrakt dla operacji finansowych. Powinien deklarować metody deposit(double amount) i withdraw(double amount), zwracające wartość logiczną informującą o powodzeniu operacji.
  • InsufficientFundsException.java: Utwórz własny wyjątek rozszerzający Exception. Konstruktor powinien przyjmować kwotę próby wypłaty i bieżące saldo, tworząc komunikat w formacie Insufficient funds: attempted [amount], available [balance].
  • Account.java: Utwórz abstrakcyjną klasę bazową reprezentującą dowolne konto bankowe. Uwzględnij prywatne pola accountNumber (String) i balance (double), konstruktor inicjalizujący oba pola, odpowiednie metody pobierające, chronioną metodę ustawiającą saldo (aby podklasy mogły je modyfikować) oraz metodę abstrakcyjną getAccountType(), która zwraca String. Zaimplementuj metodę getDetails(), która zwraca "[accountNumber] ([accountType]): $[balance]", z saldem sformatowanym do 2 miejsc po przecinku.
  • SavingsAccount.java: Utwórz klasę rozszerzającą Account i implementującą Transactable. Dodaj prywatne pole interestRate (double). Konstruktor przyjmuje accountNumber, saldo początkowe i interestRate. Zaimplementuj getAccountType(), aby zwracała "Savings". W przypadku deposit() dodaj kwotę do salda i zwróć true. W przypadku withdraw(), jeśli kwota przekracza saldo, zwróć false; w przeciwnym razie odejmij ją i zwróć true. Dodaj metodę applyInterest(), która zwiększa saldo o balance * interestRate (stopa jest przechowywana jako ułamek, więc 0.05 oznacza 5%).
  • CheckingAccount.java: Utwórz klasę rozszerzającą Account i implementującą Transactable. Dodaj prywatne pole overdraftLimit (double). Konstruktor przyjmuje accountNumber, saldo początkowe i overdraftLimit. Zaimplementuj getAccountType(), aby zwracała "Checking". W przypadku deposit() dodaj kwotę i zwróć true. W przypadku withdraw() zezwól na wypłatę, jeśli kwota jest mniejsza lub równa sumie salda i overdraftLimit; zwróć false, jeśli przekracza ten limit.
  • Bank.java: Utwórz klasę zarządzającą kontami za pomocą ArrayList. Uwzględnij metody:
    • addAccount(Account account) — dodaje konto do banku
    • findAccount(String accountNumber) — zwraca Account lub null, jeśli konto nie zostało znalezione
    • transfer(String fromAccount, String toAccount, double amount) — przelewa pieniądze między kontami, zgłaszając InsufficientFundsException, jeśli na koncie źródłowym brakuje środków. W przypadku powodzenia zwraca "Transferred $[amount] from [fromAccount] to [toAccount]"
    • getTotalDeposits() — zwraca sumę sald wszystkich kont
  • Main.java: Zbuduj swój system bankowy! Otrzymasz ciąg poleceń rozdzielonych przecinkami:
    • SAVINGS:accountNumber:balance:interestRate
    • CHECKING:accountNumber:balance:overdraftLimit
    • DEPOSIT:accountNumber:amount
    • WITHDRAW:accountNumber:amount
    • TRANSFER:fromAccount:toAccount:amount
    • INTEREST:accountNumber

    Przetwórz każde polecenie i wypisz:

    • SAVINGS/CHECKING: Account created: [accountNumber]
    • DEPOSIT: Deposited $[amount] to [accountNumber]
    • WITHDRAW: Withdrew $[amount] from [accountNumber] w przypadku powodzenia lub Withdrawal failed: [accountNumber]
    • TRANSFER: Wypisz komunikat o powodzeniu lub Transfer failed: [exception message]
    • INTEREST: Interest applied to [accountNumber]

    Po przetworzeniu wszystkich poleceń wypisz --- Bank Summary ---, a następnie szczegóły każdego konta (za pomocą getDetails()) i na końcu Total deposits: $[total], sformatowane do 2 miejsc po przecinku.

Otrzymasz jedno wejście: ciąg poleceń rozdzielonych przecinkami.

Na przykład dla wejścia SAVINGS:SAV001:1000.00:0.05,CHECKING:CHK001:500.00:200.00,DEPOSIT:SAV001:250.00,WITHDRAW:CHK001:600.00,TRANSFER:SAV001:CHK001:100.00,INTEREST:SAV001 wynikiem będzie:

Account created: SAV001
Account created: CHK001
Deposited $250.00 to SAV001
Withdrew $600.00 from CHK001
Transferred $100.00 from SAV001 to CHK001
Interest applied to SAV001
--- Bank Summary ---
SAV001 (Savings): $1207.50
CHK001 (Checking): $0.00
Total deposits: $1207.50

Zwróć uwagę, że konto rozliczeniowe pozwala wypłacić $600, mimo że saldo wynosi tylko $500 — właśnie tak działa ochrona przed debetem! Konto oszczędnościowe zyskuje 5% odsetek od salda po wykonaniu przelewu. To wyzwanie łączy dziedziczenie, interfejsy, polimorfizm, własne wyjątki i hermetyzację w realistycznej aplikacji bankowej!

Spróbuj swoich sił

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: Utwórz instancję Bank
        
        // TODO: Podziel input według przecinków, aby uzyskać poszczególne polecenia
        
        // TODO: Przetwórz każde polecenie:
        // - SAVINGS:accountNumber:balance:interestRate -> Utwórz SavingsAccount i wypisz "Account created: [accountNumber]"
        // - CHECKING:accountNumber:balance:overdraftLimit -> Utwórz CheckingAccount i wypisz "Account created: [accountNumber]"
        // - DEPOSIT:accountNumber:amount -> Wpłać środki i wypisz "Deposited $[amount] to [accountNumber]"
        // - WITHDRAW:accountNumber:amount -> Wypłać środki i wypisz komunikat o powodzeniu lub "Withdrawal failed: [accountNumber]"
        // - TRANSFER:fromAccount:toAccount:amount -> Wykonaj przelew i wypisz komunikat o powodzeniu lub "Transfer failed: [exception message]"
        // - INTEREST:accountNumber -> Nalicz odsetki i wypisz "Interest applied to [accountNumber]"
        
        // TODO: Po przetworzeniu wszystkich poleceń wypisz "--- Bank Summary ---"
        
        // TODO: Wypisz szczegóły każdego konta za pomocą getDetails()
        
        // TODO: Wypisz "Total deposits: $[total]", formatując kwotę do 2 miejsc po przecinku
    }
}
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 Java online