은행 시스템
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 104번째.
챌린지
쉬움상태(State) 패턴, 상속, 그리고 스마트 포인터 관리를 보여주는 은행 시스템을 구축해 보겠습니다. 계좌가 서로 다른 상태(Active, Frozen, Closed)에 있을 수 있고, 각 상태에 따라 트랜잭션을 처리하는 동작이 달라지는 시스템을 만들 것입니다.
코드는 다음 여섯 개의 파일로 구성됩니다:
AccountState.h: 계좌 상태를 위한 상태 패턴 인프라를 정의합니다.순수 가상 메서드를 가진 추상
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]"을 반환합니다."Basic"을 반환하는 가상getAccountType()
두 개의 파생 계좌 유형을 생성하세요:
SavingsAccount: 최소 잔액 요구 사항이 있습니다(생성자로 전달됨). withdraw를 오버라이드하여 출금 후 잔액이 최소 잔액 미만으로 떨어지는지 확인합니다. 만약 그렇다면"Cannot go below minimum balance of [minimum]"을 출력합니다. 계좌 유형으로"Savings"를 반환합니다.CheckingAccount: 마이너스 한도(overdraft limit)가 있습니다(생성자로 전달됨). (잔액 + 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: 은행 시스템을 시연합니다.네 개의 입력을 읽습니다:
- 고객 상세 정보 (형식:
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이 챌린지는 계좌 동작 관리를 위한 상태 패턴, 다양한 계좌 유형을 위한 상속, 소유권 관계를 위한 스마트 포인터, 그리고 트랜잭션 추적 등 이 과정 전반에서 익힌 핵심 개념들을 하나로 모으는 과정입니다.
직접 해보기
#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: 은행(bank) 생성하기
// TODO: 고객(customer) 생성하기
// TODO: 고객을 소유자로 하는 저축 계좌(savings account) 생성하기
// 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;
}