Menu
Coddy logo textTech

은행 시스템

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 104개 중 104번째.

challenge icon

챌린지

쉬움

상태(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: 은행 시스템을 시연합니다.

    네 개의 입력을 읽습니다:

    1. 고객 상세 정보 (형식: name,customerId)
    2. 저축 계좌 상세 정보 (형식: accountNumber,minBalance)
    3. 작업 1 (형식: action,accountNumber,amount, 여기서 action은 deposit 또는 withdraw)
    4. 작업 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;
}

객체 지향 프로그래밍의 모든 레슨