銀行システム
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 104/104。
チャレンジ
簡単State パターン、継承、スマートポインター管理を示す銀行システムを構築しましょう。アカウントが異なる状態(Active、Frozen、Closed)になり、それぞれの状態でトランザクション処理の動作が異なるシステムを作成します。
コードを6つのファイルに整理します。
AccountState.h:アカウントの状態に関する State パターンの基盤を定義します。純粋仮想メソッドを持つ抽象
AccountState基底クラスを作成します。deposit(double amount):入金が許可されている場合は true、そうでなければ false を返しますwithdraw(double amount):出金が許可されている場合は true、そうでなければ false を返しますgetStateName():状態名を文字列として返します
3つの具体的な状態を実装します。
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]"を返します"Basic"を返す仮想getAccountType()
2種類の派生アカウント型を作成します。
SavingsAccount:最低残高要件を持ちます(コンストラクターに渡されます)。withdrawをオーバーライドし、出金によって最低残高を下回るかどうかも確認します。下回る場合は"Cannot go below minimum balance of [minimum]"を出力します。アカウント種別として"Savings"を返します。CheckingAccount:当座貸越限度額を持ちます(コンストラクターに渡されます)。残高と overdraftLimit の合計までの出金を許可します。アカウント種別として"Checking"を返します。
Transaction.h:トランザクションをオブジェクトとしてモデル化します。次の情報を記録する
Transactionクラスを作成します。- トランザクション種別(文字列:"Deposit"、"Withdrawal"、"Transfer")
- 金額
- 対象となるアカウント番号
- 成功状態(bool)
"[type]: $[amount] on [accountNumber] - [Success/Failed]"を返すgetDescription()メソッドを追加します。Customer.h:複数のアカウントを所有する顧客を作成します。Customerは名前、ID、std::shared_ptr<Account>のベクターを持ちます。次を実装します。addAccount(std::shared_ptr<Account> account)getAccount(const std::string& accountNumber):一致するアカウント、または nullptr を返しますgetTotalBalance():すべてのアカウントの残高を合計します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:銀行システムを実演します。4つの入力を読み取ります。
- 顧客情報(形式:
name,customerId) - 普通預金アカウント情報(形式:
accountNumber,minBalance) - 操作1(形式:
action,accountNumber,amount。action はdepositまたはwithdraw) - 操作2(形式:
action,accountNumber,amountまたはfreeze,accountNumber)
銀行と顧客を作成します。顧客を所有者とする普通預金アカウントを作成し、それを顧客に追加します。顧客を銀行に追加します。2つの操作を処理します(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: Print transaction count as "Transactions: [count]"
return 0;
}
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ