النظام المصرفي
جزء من قسم البرمجة كائنية التوجه في رحلة Java على Coddy. الدرس 85 من 87.
يتحدّاك هذا التمرين ببناء نظام مصرفي يحاكي العمليات المالية في العالم الحقيقي باستخدام مبادئ البرمجة كائنية التوجه.
يجب أن يتعامل نظامك مع أنواع مختلفة من الحسابات مثل SavingsAccount وCheckingAccount، وكلاهما يمتد من فئة أساسية هي Account. لكل نوع من الحسابات سلوكيات فريدة: فقد تكسب حسابات التوفير فائدة، بينما قد تتمتع الحسابات الجارية بحماية من السحب على المكشوف.
فكّر في كيفية نمذجة المعاملات. يمكن لواجهة مثل Transactable أن تحدّد أساليب لـ deposit() وwithdraw(). فكّر في استخدام استثناءات مخصّصة مثل InsufficientFundsException لمعالجة العمليات غير الصالحة بسلاسة.
قد تدير فئة Bank حسابات وعملاء متعدّدين، موضّحةً مفهوم التركيب. يمكنك تطبيق نمط Factory لإنشاء أنواع مختلفة من الحسابات، أو استخدام نمط Observer لإخطار العملاء بتغييرات الحساب.
ركّز على التغليف لحماية البيانات الحساسة مثل balances وأرقام account، واستخدم تعدد الأشكال لمعالجة أنواع account المختلفة بشكل موحّد.
التحدي
سهللنبنِ نظامًا مصرفيًا متكاملًا يبرهن على إتقانك لمبادئ البرمجة كائنية التوجه! ستنشئ نظامًا يتضمن أنواعًا مختلفة من الحسابات، ومعالجة المعاملات، وإدارة الاستثناءات بطريقة صحيحة، وكل ذلك منظّم عبر ملفات متعددة.
ستنظّم شيفرتك عبر سبعة ملفات:
Transactable.java: أنشئ واجهة تحدد العقد الخاص بالعمليات المالية. يجب أن تعلن عن الطريقتينdeposit(double amount)وwithdraw(double amount)، وكلتاهما تعيدان قيمة منطقية للإشارة إلى النجاح.InsufficientFundsException.java: أنشئ استثناءً مخصصًا يمتد منException. يجب أن يستقبل المُنشئ مبلغ السحب attempted والرصيد الحالي، وأن ينشئ رسالة بالتنسيقInsufficient funds: attempted [amount], available [balance].Account.java: أنشئ فئة أساسية مجردة تمثل أي حساب مصرفي. أدرج حقولًا خاصة لـaccountNumberمن النوع String وbalanceمن النوع double، ومُنشئًا يهيّئ كليهما، وواحدات وصول مناسبة، وsetter محميًا للـ balance (حتى تتمكن الفئات الفرعية من تعديله)، وطريقة مجردةgetAccountType()تعيد قيمة من النوع String. نفّذ طريقةgetDetails()التي تعيد"[accountNumber] ([accountType]): $[balance]"مع تنسيق balance ليظهر حتى منزلتين عشريتين.SavingsAccount.java: أنشئ فئة تمتد منAccountوتنفّذTransactable. أضف حقلًا خاصًا لـinterestRateمن النوع double. يستقبل المُنشئ accountNumber وbalance الابتدائي وinterestRate. نفّذgetAccountType()لتعيد"Savings". بالنسبة إلىdeposit()، أضف المبلغ إلى balance وأعد true. وبالنسبة إلىwithdraw()، إذا تجاوز المبلغ balance فأعد false؛ وإلا اطرح المبلغ وأعد true. أضف طريقةapplyInterest()تزيد balance بمقدارbalance * interestRate(يُخزَّن المعدل على شكل كسر، لذا فإن0.05تعني 5%).CheckingAccount.java: أنشئ فئة تمتد منAccountوتنفّذTransactable. أضف حقلًا خاصًا لـoverdraftLimitمن النوع double. يستقبل المُنشئ accountNumber وbalance الابتدائي وoverdraftLimit. نفّذgetAccountType()لتعيد"Checking". بالنسبة إلىdeposit()، أضف المبلغ وأعد true. وبالنسبة إلىwithdraw()، اسمح بالسحب إذا كان المبلغ أقل من أو يساوي balance زائد 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:interestRateCHECKING:accountNumber:balance:overdraftLimitDEPOSIT:accountNumber:amountWITHDRAW:accountNumber:amountTRANSFER:fromAccount:toAccount:amountINTEREST: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: تقسيم الإدخال بواسطة الفاصلة للحصول على الأوامر المنفردة
// TODO: معالجة كل أمر:
// - SAVINGS:accountNumber:balance:interestRate -> Create SavingsAccount, print "Account created: [accountNumber]"
// - CHECKING:accountNumber:balance:overdraftLimit -> Create CheckingAccount, print "Account created: [accountNumber]"
// - DEPOSIT:accountNumber:amount -> قم بالإيداع واطبع "Deposited $[amount] to [accountNumber]"
// - WITHDRAW:accountNumber:amount -> Withdraw and print success or "Withdrawal failed: [accountNumber]"
// - TRANSFER:fromAccount:toAccount:amount -> قم بالتحويل واطبع نجاح العملية أو "Transfer failed: [exception message]"
// - INTEREST:accountNumber -> Apply interest and print "Interest applied to [accountNumber]"
// TODO: بعد تنفيذ جميع الأوامر، اطبع "--- Bank Summary ---"
// TODO: طباعة تفاصيل كل حساب باستخدام getDetails()
// TODO: Print "Total deposits: $[total]" formatted to 2 decimal places
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكررتدرّب بنفسك: مترجم Java عبر الإنترنت