מערכת בנקאית
חלק מהיחידה תכנות מונחה עצמים במסלול ה-C++ של Coddy. שיעור 104 מתוך 104.
אתגר
קלבואו נבנה מערכת בנקאית המדגימה את תבנית State, ירושה וניהול מצביעים חכמים. תיצרו מערכת שבה חשבונות יכולים להיות במצבים שונים (Active, Frozen, Closed), ולכל מצב התנהגויות ייחודיות לטיפול בעסקאות.
תארגנו את הקוד שלכם בשישה קבצים:
AccountState.h: הגדירו את התשתית של תבנית State למצבי חשבון.צרו מחלקת בסיס מופשטת בשם
AccountStateעם מתודות וירטואליות טהורות:deposit(double amount): מחזירה true אם הפקדה מותרת, ו-false אחרתwithdraw(double amount): מחזירה true אם משיכה מותרת, ו-false אחרתgetStateName(): מחזירה את שם המצב כמחרוזת
ממשו שלושה מצבים קונקרטיים:
ActiveState: מאפשרת הפקדות ומשיכות, ומחזירה"Active"FrozenState: מאפשרת הפקדות אך דוחה משיכות, ומחזירה"Frozen"ClosedState: דוחה הפקדות ומשיכות, ומחזירה"Closed"
Account.h: בנו היררכיית חשבונות עם ניהול מצבים.צרו מחלקת בסיס בשם
Accountעם:- מספר חשבון (מחרוזת), שם בעל החשבון ויתרה
std::unique_ptr<AccountState>לניהול המצב הנוכחיdeposit(double amount): בודקת קודם מול המצב; אם ההפקדה מותרת, מוסיפה את הסכום ליתרה ומדפיסה"Deposited [amount] to [accountNumber]", אחרת מדפיסה"Deposit rejected: account is [stateName]"withdraw(double amount): בודקת מול המצב; אם המשיכה מותרת ויש מספיק כסף, מנכה את הסכום ומדפיסה"Withdrew [amount] from [accountNumber]". אם המצב דוחה את המשיכה, הדפיסו"Withdrawal rejected: account is [stateName]". אם אין מספיק כסף, הדפיסו"Insufficient funds"freeze(),activate()ו-close(): משנות את מצב החשבוןgetInfo(): מחזירה"[accountNumber] ([ownerName]): $[balance] - [stateName]"getAccountType()וירטואלית, שמחזירה"Basic"
צרו שני סוגי חשבון נגזרים:
SavingsAccount: יש לה דרישת יתרת מינימום (המועברת לבנאי). דרסו את withdraw כך שתבדוק גם אם המשיכה תוריד את היתרה מתחת למינימום; אם כן, הדפיסו"Cannot go below minimum balance of [minimum]". סוג החשבון שמוחזר הוא"Savings".CheckingAccount: יש לה מסגרת משיכת יתר (המועברת לבנאי). היא מאפשרת משיכות עד לגובה (היתרה + overdraftLimit). סוג החשבון שמוחזר הוא"Checking".
Transaction.h: ייצגו עסקאות כאובייקטים.צרו מחלקה בשם
Transactionשמתעדת:- סוג העסקה (מחרוזת: "Deposit", "Withdrawal", "Transfer")
- סכום
- מספר החשבון המעורב
- מצב הצלחה (bool)
הוסיפו מתודה בשם
getDescription()שמחזירה"[type]: $[amount] on [accountNumber] - [Success/Failed]"Customer.h: צרו לקוח שבבעלותו מספר חשבונות.ל-
Customerיש שם, מזהה ווקטור שלstd::shared_ptr<Account>. ממשו:addAccount(std::shared_ptr<Account> account)getAccount(const std::string& accountNumber): מחזירה את החשבון התואם או nullptrgetTotalBalance(): מסכמת את היתרות בכל החשבונותlistAccounts(): מדפיסה את הפרטים של כל חשבון
Bank.h: תזמרו את הפעולות הבנקאיות.המחלקה
Bankמאחסנת לקוחות ומנהלת היסטוריית עסקאות. ממשו:addCustomer(std::shared_ptr<Customer> customer)findAccount(const std::string& accountNumber): מחפשת את החשבון אצל כל הלקוחותprocessDeposit(const std::string& accountNumber, double amount): מוצאת את החשבון, מבצעת הפקדה ומתעדת את העסקהprocessWithdrawal(const std::string& accountNumber, double amount): מוצאת את החשבון, מבצעת משיכה ומתעדת את העסקהgetTransactionCount(): מחזירה את מספר העסקאות הכולל שעובדו
main.cpp: הדגימו את המערכת הבנקאית שלכם.קראו ארבע שורות קלט:
- פרטי הלקוח (בפורמט:
name,customerId) - פרטי חשבון החיסכון (בפורמט:
accountNumber,minBalance) - פעולה 1 (בפורמט:
action,accountNumber,amount, כאשר action הואdepositאוwithdraw) - פעולה 2 (בפורמט:
action,accountNumber,amountאוfreeze,accountNumber)
צרו את הבנק ואת הלקוח. צרו חשבון חיסכון שבעליו הוא הלקוח, והוסיפו אותו ללקוח. הוסיפו את הלקוח לבנק. עבדו את שתי הפעולות (אם זו פקודת freeze, הקפיאו את החשבון ואז נסו לבצע משיכה קטנה של $10 כדי להדגים את המצב). לבסוף, הדפיסו את רשימת חשבונות הלקוח ואת מספר העסקאות הכולל בפורמט
"Transactions: [count]".- פרטי הלקוח (בפורמט:
לדוגמה, עבור הקלט Alice,C001, SAV001,100, deposit,SAV001,500 ו-withdraw,SAV001,200:
Deposited 500 to SAV001
Withdrew 200 from SAV001
SAV001 (Alice): $300 - Active
Transactions: 2עבור הקלט Bob,C002, SAV002,50, deposit,SAV002,100 ו-freeze,SAV002:
Deposited 100 to SAV002
Withdrawal rejected: account is Frozen
SAV002 (Bob): $100 - Frozen
Transactions: 2עבור הקלט Carol,C003, SAV003,200, deposit,SAV003,250 ו-withdraw,SAV003,100:
Deposited 250 to SAV003
Cannot go below minimum balance of 200
SAV003 (Carol): $250 - Active
Transactions: 2האתגר הזה משלב את תבנית State לניהול התנהגויות החשבונות, ירושה לסוגי חשבון שונים, מצביעים חכמים לניהול קשרי בעלות ומעקב אחר עסקאות: כל המושגים המרכזיים שלמדתם לאורך הקורס.
נסו בעצמכם
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include "Bank.h"
int main() {
// קרא את קלט 1: פרטי הלקוח (פורמט: name,customerId)
std::string customerInput;
std::getline(std::cin, customerInput);
// קרא את קלט 2: פרטי חשבון החיסכון (פורמט: accountNumber,minBalance)
std::string accountInput;
std::getline(std::cin, accountInput);
// קרא את קלט 3: פעולה 1 (פורמט: action,accountNumber,amount)
std::string op1Input;
std::getline(std::cin, op1Input);
// קרא את קלט 4: פעולה 2 (פורמט: action,accountNumber,amount או freeze,accountNumber)
std::string op2Input;
std::getline(std::cin, op2Input);
// TODO: נתח את פרטי הלקוח מתוך customerInput
// רמז: השתמש ב-find(',') כדי לפצל את המחרוזת
// TODO: נתח את פרטי החשבון מתוך accountInput
// TODO: צור את הבנק
// TODO: צור את הלקוח
// TODO: צור חשבון חיסכון שהלקוח הוא בעליו
// TODO: הוסף את החשבון ללקוח
// TODO: הוסף את הלקוח לבנק
// TODO: פענח ועבד את פעולה 1
// פורמט: action,accountNumber,amount (הערך של action הוא "deposit" או "withdraw")
// TODO: פענח ועבד את פעולה 2
// יכול להיות: action,accountNumber,amount או freeze,accountNumber
// אם הפעולה היא freeze, הקפא את החשבון ואז נסה למשוך $10
// TODO: הדפס את רשימת החשבונות של הלקוח
// TODO: הדפס את מספר העסקאות בפורמט "Transactions: [count]"
return 0;
}
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות OOP
קבצים חיצונייםבנייה וקומפילציה של C++קובצי Header וקובצי מקורמרחבי שמות והיקףמבוא ל-OOP ב-C++מחלקות לעומת אובייקטיםמצביע thisמתודות (פונקציות איבר)תכונות (חברי נתונים)יסודות הבנאים וההורסיםסיכום – מחשבון פשוט4מאפייני מחלקה
חברי מופע לעומת חברים סטטייםגטרים וסטריםפונקציות איבר קבועותמילת המפתח mutableמתודות ומשתנים סטטייםפונקציות ומחלקות ידידותסיכום – מנהל חשבונות בנק7ירושה
ירושה בסיסיתרמות גישה בירושהסדר הקריאות לבנאי ולמפרקדריסת מתודותפונקציות וירטואליות ו־VTableירושה מרובהירושה וירטואליתסיכום – היררכיית עובדים2ניהול זיכרון
זיכרון Stack לעומת Heapמצביעים והפניותזיכרון דינמי (new/delete)מצביעים חכמים ב-C++RAII ב-C++סיכום – מנהל מערכים דינמיים5כימוס
מצייני גישה ב-C++מצייני גישה לעומקהסתרת מידעמבנה לעומת מחלקהמחלקות מקוננות ופנימיותסיכום – מערכת רשומות תלמידים8רב־צורתיות
רב־צורתיות בזמן קומפילציה לעומת בזמן ריצההעמסת פונקציותפונקציות וירטואליות — מבט נוסףפונקציות וירטואליות טהורותמחלקות מופשטותתכנון ממשקים ב־C++המרה דינמית ו־RTTIסיכום — מחשבון צורות3בנאים והורסים
בנאי ברירת מחדלבנאי עם פרמטריםבנאי העתקהבנאי העברהרשימות אתחול בבנאיםבנאים מאציליםמעמיקים בנושא הורסיםכלל השלושה / החמישה / האפססיכום – מחלקת String6העמסת אופרטורים
מבוא להעמסת אופרטוריםהעמסת אופרטורים אריתמטייםהעמסת אופרטורי השוואהאופרטורי זרםהעמסת אופרטור השמההעמסת האופרטורים [] ו־()אופרטורים להמרת טיפוסיםסיכום – מחלקת Matrix9תבניות
תבניות פונקציהתבניות מחלקההתמחות תבניותתבניות ארגומנטים משתנותיסודות SFINAE ותכונות טיפוסיםסיכום – מכל גנריתרגלו בעצמכם: קומפיילר C++ אונליין