Menu
Coddy logo textTech

은행 시스템

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

challenge icon

챌린지

쉬움

State 패턴, 상속, 스마트 포인터 관리를 보여 주는 Banking System을 만들어 봅시다. 트랜잭션을 처리하는 동작이 각각 다른 여러 상태(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 클래스를 만듭니다:

    • 계정 번호(string), 소유자 이름, 잔액
    • 현재 상태를 관리하기 위한 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: 초과 인출 한도가 있습니다(생성자에 전달). (잔액 + overdraftLimit)까지 출금을 허용합니다. 계정 유형으로 "Checking"을 반환합니다.
  • Transaction.h: 트랜잭션을 객체로 모델링합니다.

    다음 정보를 기록하는 Transaction 클래스를 만듭니다:

    • 트랜잭션 유형(string: "Deposit", "Withdrawal", "Transfer")
    • 금액
    • 관련 계정 번호
    • 성공 상태(bool)

    "[type]: $[amount] on [accountNumber] - [Success/Failed]"를 반환하는 getDescription() 메서드를 추가합니다

  • Customer.h: 여러 계정을 소유하는 고객을 만듭니다.

    Customer는 이름, ID, 그리고 std::shared_ptr<Account>의 vector를 가집니다. 다음을 구현합니다:

    • 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: Banking System을 시연합니다.

    네 가지 입력을 읽습니다:

    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

이 challenge에서는 계정 동작을 관리하기 위한 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++ 컴파일러