النظام المصرفي
جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 85 من 87.
تطلب منك هذه المهمة بناء نظام بنكي يحاكي العمليات المالية في العالم الحقيقي باستخدام مبادئ البرمجة كائنية التوجه (OOP).
يجب أن يتعامل نظامك مع أنواع حسابات مختلفة مثل SavingsAccount و CheckingAccount، وكلاهما يرث من فئة Account الأساسية. لكل نوع حساب سلوكيات فريدة: فقد تكسب حسابات التوفير فوائد، بينما قد تحتوي الحسابات الجارية على حماية من السحب على المكشوف.
فكر في كيفية نمذجة المعاملات. واجهة مثل Transactable يمكن أن تحدد طرقاً لـ deposit() و withdraw(). فكر في استخدام استثناءات مخصصة مثل InsufficientFundsException لمعالجة العمليات غير الصالحة بشكل سلس.
قد تقوم فئة Bank بإدارة حسابات وعملاء متعددين، مما يوضح مفهوم التركيب (composition). يمكنك تطبيق نمط المصنع (Factory pattern) لإنشاء أنواع حسابات مختلفة، أو استخدام نمط المراقب (Observer pattern) لإخطار العملاء بتغييرات الحساب.
ركز على التغليف (encapsulation) لحماية البيانات الحساسة مثل الأرصدة وأرقام الحسابات، واستخدم تعدد الأشكال (polymorphism) لمعالجة أنواع الحسابات المختلفة بشكل موحد.
التحدي
سهللنقم ببناء نظام بنكي كامل يوضح إتقانك لمبادئ البرمجة كائنية التوجه (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) تمثل أي حساب بنكي. قم بتضمين حقول خاصة لـaccountNumber(String) وbalance(double)، ومنشئ يقوم بتهيئة كليهما، وطرق جلب (getters) مناسبة، وطريقة تعيين (setter) محمية للرصيد (حتى تتمكن الفئات الفرعية من تعديله)، وطريقة مجردةgetAccountType()تعيد String. قم بتنفيذ طريقةgetDetails()التي تعيد"[accountNumber] ([accountType]): $[balance]"مع تنسيق الرصيد إلى منزلتين عشريتين.SavingsAccount.java: أنشئ فئة ترث منAccountوتنفذTransactable. أضف حقلاً خاصاً لـinterestRate(double). يأخذ المنشئ accountNumber، والرصيد الأولي، و interestRate. قم بتنفيذgetAccountType()لتعيد"Savings". بالنسبة لـdeposit()، أضف المبلغ إلى الرصيد وأعد true. بالنسبة لـwithdraw()، إذا تجاوز المبلغ الرصيد، أعد false؛ خلاف ذلك اطرح المبلغ وأعد true. أضف طريقةapplyInterest()تزيد الرصيد بنسبة سعر الفائدة.CheckingAccount.java: أنشئ فئة ترث منAccountوتنفذTransactable. أضف حقلاً خاصاً لـoverdraftLimit(double). يأخذ المنشئ accountNumber، والرصيد الأولي، و 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: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 account) بسحب 600 دولار على الرغم من وجود رصيد 500 دولار فقط—هذه هي حماية السحب على المكشوف (overdraft protection) أثناء العمل! يربح حساب التوفير فائدة بنسبة 5% على رصيده بعد التحويل. يجمع هذا التحدي بين الوراثة، والواجهات، وتعدد الأشكال، والاستثناءات المخصصة، والتغليف في تطبيق بنكي واقعي!
ورقة مرجعية
يوضح النظام المصرفي مبادئ البرمجة كائنية التوجه (OOP) من خلال إدارة الحسابات، والمعاملات، ومعالجة الاستثناءات.
الواجهات للعقود (Interfaces for Contracts)
حدد العمليات المشتركة باستخدام الواجهات:
public interface Transactable {
boolean deposit(double amount);
boolean withdraw(double amount);
}الاستثناءات المخصصة (Custom Exceptions)
قم بإنشاء استثناءات مخصصة للأخطاء الخاصة بالمجال:
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(double attempted, double available) {
super("Insufficient funds: attempted " + attempted + ", available " + available);
}
}الفئات الأساسية المجردة (Abstract Base Classes)
استخدم الفئات المجردة لتعريف هيكل مشترك مع طرق مجردة للسلوك الخاص بالفئات الفرعية:
public abstract class Account {
private String accountNumber;
private double balance;
public abstract String getAccountType();
protected void setBalance(double balance) {
this.balance = balance;
}
}الوراثة وتعدد الأشكال (Inheritance and Polymorphism)
تقوم الفئات الفرعية بتوسيع الفئات الأساسية وتنفيذ الواجهات:
public class SavingsAccount extends Account implements Transactable {
private double interestRate;
@Override
public String getAccountType() {
return "Savings";
}
public void applyInterest() {
setBalance(getBalance() * (1 + interestRate));
}
}التكوين (Composition)
يمكن للفئات إدارة مجموعات من الكائنات الأخرى:
public class Bank {
private ArrayList<Account> accounts;
public void addAccount(Account account) {
accounts.add(account);
}
public Account findAccount(String accountNumber) {
// البحث وإرجاع الحساب أو null
}
}التغليف (Encapsulation)
قم بحماية البيانات الحساسة باستخدام الحقول الخاصة (private fields) والوصول المتحكم فيه من خلال دوال الجلب والتعيين (getters/setters). استخدم معدلات protected للسماح بالوصول للفئات الفرعية مع الحفاظ على التغليف.
معالجة الاستثناءات في المعاملات
قم برمي استثناءات مخصصة للعمليات غير الصالحة:
public String transfer(String from, String to, double amount) throws InsufficientFundsException {
if (!fromAccount.withdraw(amount)) {
throw new InsufficientFundsException(amount, fromAccount.getBalance());
}
toAccount.deposit(amount);
return "Transferred $" + amount;
}جرّب بنفسك
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]" بتنسيق منزلتين عشريتين
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
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أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكرر