Menu
Coddy logo textTech

銀行システム

CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 104/104。

challenge icon

チャレンジ

簡単

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つの入力を読み取ります。

    1. 顧客情報(形式:name,customerId
    2. 普通預金アカウント情報(形式:accountNumber,minBalance
    3. 操作1(形式:action,accountNumber,amount。action はdepositまたはwithdraw
    4. 操作2(形式:action,accountNumber,amountまたはfreeze,accountNumber

    銀行と顧客を作成します。顧客を所有者とする普通預金アカウントを作成し、それを顧客に追加します。顧客を銀行に追加します。2つの操作を処理します(freeze コマンドの場合は、状態を示すためにアカウントを凍結してから少額の $10 の出金を試みます)。最後に、顧客のアカウント一覧と、"Transactions: [count]"としてトランザクション総数を出力します。

たとえば、入力がAlice,C001SAV001,100deposit,SAV001,500withdraw,SAV001,200の場合:

Deposited 500 to SAV001
Withdrew 200 from SAV001
SAV001 (Alice): $300 - Active
Transactions: 2

入力がBob,C002SAV002,50deposit,SAV002,100freeze,SAV002の場合:

Deposited 100 to SAV002
Withdrawal rejected: account is Frozen
SAV002 (Bob): $100 - Frozen
Transactions: 2

入力がCarol,C003SAV003,200deposit,SAV003,250withdraw,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;
}

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C++オンラインコンパイラ