Menu
CoddyTech

النظام المصرفي

جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 85 من 87.

يتحداك هذا التمرين ببناء نظام مصرفي يحاكي العمليات المالية في العالم الحقيقي باستخدام مبادئ البرمجة كائنية التوجه (OOP).

ينبغي لنظامك التعامل مع أنواع مختلفة من الحسابات مثل SavingsAccount وCheckingAccount، وكلاهما يرث من الفئة الأساسية Account. لكل نوع حساب سلوكيات فريدة: فقد تكتسب حسابات التوفير فوائد، بينما قد تتمتع الحسابات الجارية بحماية من السحب على المكشوف.

فكّر في كيفية نمذجة المعاملات. يمكن لواجهة مثل Transactable أن تعرّف أساليبًا للإيداع والسحب عبر deposit() وwithdraw(). فكّر في استخدام استثناءات مخصصة مثل InsufficientFundsException لمعالجة العمليات غير الصالحة بسلاسة.

قد تدير الفئة Bank عدة حسابات وعملاء، موضحةً التركيب. يمكنك تطبيق نمط المصنع لإنشاء أنواع مختلفة من الحسابات، أو استخدام نمط المراقب لإخطار العملاء بتغييرات الحساب.

ركّز على التغليف لحماية البيانات الحساسة مثل الأرصدة وأرقام الحسابات، واستخدم تعدد الأشكال لمعالجة أنواع الحسابات المختلفة بطريقة موحّدة.

challenge icon

التحدي

سهل

لنبنِ نظامًا مصرفيًا متكاملًا يُظهر إتقانك لمبادئ البرمجة كائنية التوجه! ستنشئ نظامًا يتضمن أنواعًا مختلفة من الحسابات، ومعالجة المعاملات، وإدارة الاستثناءات بشكل سليم، وكل ذلك موزع على عدة ملفات.

ستوزع الكود على سبعة ملفات:

  • Transactable.java: أنشئ واجهة تحدد العقد الخاص بالعمليات المالية. يجب أن تعلن عن الدالتين deposit(double amount) وwithdraw(double amount)، على أن تعيدا كلتاهما قيمة منطقية للإشارة إلى النجاح.
  • InsufficientFundsException.java: أنشئ استثناءً مخصصًا يرث من Exception. يجب أن يقبل المُنشئ مبلغ السحب المطلوب والرصيد الحالي، وأن ينشئ رسالة بالتنسيق Insufficient funds: attempted [amount], available [balance].
  • Account.java: أنشئ فئة أساسية مجردة تمثل أي حساب مصرفي. أضف حقولًا خاصة لـ accountNumber (String) وbalance (double)، ومُنشئًا يهيئ كليهما، ودوال الحصول المناسبة، ودالة تعيين محمية للرصيد (كي تتمكن الفئات الفرعية من تعديله)، ودالة مجردة getAccountType() تعيد قيمة من النوع String. نفّذ الدالة getDetails() لتعيد "[accountNumber] ([accountType]): $[balance]" مع تنسيق الرصيد إلى منزلتين عشريتين.
  • SavingsAccount.java: أنشئ فئة ترث من Account وتنفّذ Transactable. أضف حقلًا خاصًا لـ interestRate (double). يستقبل المُنشئ accountNumber والرصيد الابتدائي وinterestRate. نفّذ getAccountType() لتعيد "Savings". في deposit()، أضف المبلغ إلى الرصيد وأعد true. في withdraw()، إذا تجاوز المبلغ الرصيد، فأعد false؛ وإلا اطرح المبلغ وأعد true. أضف دالة applyInterest() تزيد الرصيد بمقدار balance * interestRate (يُخزَّن المعدل ككسر، لذا فإن 0.05 تعني 5%).
  • CheckingAccount.java: أنشئ فئة ترث من Account وتنفّذ Transactable. أضف حقلًا خاصًا لـ overdraftLimit (double). يستقبل المُنشئ accountNumber والرصيد الابتدائي وoverdraftLimit. نفّذ getAccountType() لتعيد "Checking". في deposit()، أضف المبلغ وأعد true. في withdraw()، اسمح بالسحب إذا كان المبلغ أقل من الرصيد مضافًا إليه overdraftLimit أو مساويًا له؛ وأعد false إذا تجاوز هذا الحد.
  • Bank.java: أنشئ فئة تدير الحسابات باستخدام ArrayList. أضف الدوال التالية:
    • addAccount(Account account) - تضيف حسابًا إلى البنك
    • findAccount(String accountNumber) - تعيد Account أو null إذا لم يُعثر على الحساب
    • transfer(String fromAccount, String toAccount, double amount) - تحوّل الأموال بين الحسابات، وتطلق InsufficientFundsException إذا لم يكن في الحساب المصدر أموال كافية. عند النجاح، أعد "Transferred $[amount] from [fromAccount] to [toAccount]"
    • getTotalDeposits() - تعيد مجموع أرصدة جميع الحسابات
  • Main.java: أنشئ نظامك المصرفي! ستتلقى سلسلة أوامر مفصولة بفواصل:
    • SAVINGS:accountNumber:balance:interestRate
    • CHECKING:accountNumber:balance:overdraftLimit
    • DEPOSIT:accountNumber:amount
    • WITHDRAW:accountNumber:amount
    • TRANSFER:fromAccount:toAccount:amount
    • INTEREST:accountNumber

    عالج كل أمر واطبع:

    • SAVINGS/CHECKING: Account created: [accountNumber]
    • DEPOSIT: Deposited $[amount] to [accountNumber]
    • WITHDRAW: Withdrew $[amount] from [accountNumber] عند النجاح، أو Withdrawal failed: [accountNumber]
    • TRANSFER: اطبع رسالة النجاح أو Transfer failed: [exception message]
    • INTEREST: Interest applied to [accountNumber]

    بعد معالجة جميع الأوامر، اطبع --- Bank Summary ---، ثم تفاصيل كل حساب (باستخدام getDetails())، وأخيرًا Total deposits: $[total] مع تنسيق القيمة إلى منزلتين عشريتين.

ستتلقى مُدخلًا واحدًا: سلسلة الأوامر المفصولة بفواصل.

على سبيل المثال، إذا كان المُدخل 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، فسيكون الناتج:

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

لاحظ كيف يسمح حساب Checking بسحب 600$ رغم أن رصيده لا يتجاوز 500$؛ فهذه هي حماية السحب على المكشوف أثناء العمل! يكتسب حساب Savings فائدة بنسبة 5% على رصيده بعد التحويل. يجمع هذا التحدي بين الوراثة والواجهات وتعدد الأشكال والاستثناءات المخصصة والتغليف في تطبيق مصرفي واقعي!

جرّب بنفسك

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();
        
        // TODO: أنشئ كائنًا من Bank
        
        // TODO: قسّم input باستخدام الفاصلة للحصول على الأوامر الفردية
        
        // TODO: عالج كل أمر:
        // - SAVINGS:accountNumber:balance:interestRate -> أنشئ SavingsAccount، واطبع "Account created: [accountNumber]"
        // - CHECKING:accountNumber:balance:overdraftLimit -> أنشئ CheckingAccount، واطبع "Account created: [accountNumber]"
        // - DEPOSIT:accountNumber:amount -> أودع المبلغ واطبع "Deposited $[amount] to [accountNumber]"
        // - WITHDRAW:accountNumber:amount -> اسحب المبلغ واطبع رسالة النجاح أو "Withdrawal failed: [accountNumber]"
        // - TRANSFER:fromAccount:toAccount:amount -> حوّل المبلغ واطبع رسالة النجاح أو "Transfer failed: [exception message]"
        // - INTEREST:accountNumber -> طبّق الفائدة واطبع "Interest applied to [accountNumber]"
        
        // TODO: بعد تنفيذ جميع الأوامر، اطبع "--- Bank Summary ---"
        
        // TODO: اطبع تفاصيل كل حساب باستخدام getDetails()
        
        // TODO: اطبع "Total deposits: $[total]" بتنسيق يتضمن منزلتين عشريتين
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Java عبر الإنترنت