Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

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

جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 85 من 87.

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

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

فكر في كيفية نمذجة المعاملات. واجهة مثل Transactable يمكنها تعريف طرق لـ deposit() و withdraw(). فكر في استخدام استثناءات مخصصة مثل InsufficientFundsException لمعالجة العمليات غير الصالحة بشكل سلس.

قد تقوم فئة Bank بإدارة حسابات وعملاء متعددين، مما يوضح مفهوم التركيب (composition). يمكنك تطبيق نمط المصنع (Factory pattern) لإنشاء أنواع حسابات مختلفة، أو استخدام نمط المراقب (Observer pattern) لإخطار العملاء بتغييرات الحساب.

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

challenge icon

التحدي

سهل

لنقم ببناء نظام بنكي كامل يوضح إتقانك لمبادئ البرمجة كائنية التوجه (OOP)! ستقوم بإنشاء نظام بأنواع حسابات مختلفة، ومعالجة المعاملات، وإدارة الاستثناءات بشكل صحيح — وكل ذلك منظم عبر ملفات متعددة.

ستقوم بتنظيم الكود الخاص بك عبر سبعة ملفات:

  • Transactable.java: أنشئ واجهة (interface) تحدد العقد للعمليات المالية. يجب أن تصرح عن الطرق deposit(double amount) و withdraw(double amount)، وكلاهما يعيد قيمة منطقية (boolean) للإشارة إلى النجاح.
  • InsufficientFundsException.java: أنشئ استثناءً مخصصاً يرث من Exception. يجب أن يقبل منشئ الفئة (constructor) مبلغ السحب المحاول والرصيد الحالي، مع إنشاء رسالة بالتنسيق Insufficient funds: attempted [amount], available [balance].
  • Account.java: أنشئ فئة أساسية مجردة (abstract base class) تمثل أي حساب بنكي. قم بتضمين حقول خاصة (private) لـ accountNumber (String) و balance (double)، ومنشئ فئة يقوم بتهيئة كليهما، وطرق جلب (getters) مناسبة، وطريقة تعيين (setter) محمية (protected) للرصيد (حتى تتمكن الفئات الفرعية من تعديله)، وطريقة مجردة getAccountType() تعيد String. قم بتنفيذ طريقة getDetails() التي تعيد "[accountNumber] ([accountType]): $[balance]" مع تنسيق الرصيد إلى منزلتين عشريتين.
  • SavingsAccount.java: أنشئ فئة ترث من Account وتنفذ Transactable. أضف حقلاً خاصاً لـ interestRate (double). يأخذ منشئ الفئة accountNumber، و balance الأولي، و interestRate. قم بتنفيذ getAccountType() لتعيد "Savings". بالنسبة لـ deposit()، أضف المبلغ إلى الرصيد وأعد true. بالنسبة لـ withdraw()، إذا تجاوز المبلغ الرصيد، أعد false؛ خلاف ذلك اطرح المبلغ وأعد true. أضف طريقة applyInterest() تزيد الرصيد بمقدار balance * interestRate (يتم تخزين المعدل ككسر، لذا فإن 0.05 تعني 5%).
  • CheckingAccount.java: أنشئ فئة ترث من Account وتنفذ Transactable. أضف حقلاً خاصاً لـ overdraftLimit (double). يأخذ منشئ الفئة accountNumber، و balance الأولي، و overdraftLimit. قم بتنفيذ getAccountType() لتعيد "Checking". بالنسبة لـ deposit()، أضف المبلغ وأعد true. بالنسبة لـ withdraw()، اسمح بالسحب إذا كان المبلغ أقل من أو يساوي الرصيد بالإضافة إلى overdraftLimit؛ وأعد false إذا تجاوز هذا الحد.
  • Bank.java: أنشئ فئة تدير الحسابات باستخدام ArrayList. قم بتضمين الطرق التالية:
    • addAccount(Account account) - يضيف حساباً إلى البنك
    • findAccount(String accountNumber) - يعيد الحساب أو 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 account) بسحب 600 دولار رغم أن رصيده 500 دولار فقط — هذه هي حماية السحب على المكشوف (overdraft protection) أثناء العمل! يحصل حساب التوفير (savings account) على فائدة بنسبة 5% على رصيده بعد التحويل. يجمع هذا التحدي بين الوراثة، والواجهات، وتعدد الأشكال (polymorphism)، والاستثناءات المخصصة، والتغليف (encapsulation) في تطبيق بنكي واقعي!

جرّب بنفسك

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: تقسيم المدخلات بواسطة الفاصلة للحصول على الأوامر الفردية
        
        // 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اختبر نفسك

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

جميع دروس Object Oriented Programming