[Java] 심화 - 은행 계좌 시스템 구조를 통한 인터페이스 실무형태 예제

이지연·2025년 12월 19일

개요

아래의 내용은 java_grammer 레파지토리 C03Inheritance 디렉터리에 저장되어있는 내용을 정리함

MVC 또는 계층형 아키텍처 구조(Entity - Service - Controller)를 모형화한 예시이다.


프로그램 구조 개요

전체 프로그램은 다음 3계층 구조로 구성되어 있음.

계층클래스역할
Entity 계층BankAccount계좌 객체의 상태(데이터)를 관리하는 영역
Service 계층BankService, BankKakaoService, BankTossService핵심 로직(입금, 출금, 검증 등)을 담당
Controller 계층BankController사용자 입력을 받아 서비스 로직을 호출하는 영역

이 구조는 의존성 분리 원칙(Dependency Separation)을 반영한 기본적인 설계 패턴임.


① Entity 계층 — BankAccount

BankAccount 클래스는 실제 은행 계좌의 데이터를 담는 엔티티 객체(entity)임.
DB의 table을 가정한 데이터 구조로 이해하면 됨.

package C04Interface.BankProgram;

public class BankAccount {
    private String accountNumber; // 계좌번호
    private long balance;         // 잔액

    public BankAccount(String accountNumber, long balance) {
        this.accountNumber = accountNumber;
        this.balance = balance;
    }

    // 입금/출금을 위한 잔액 변경 메서드
    public void updateBalance(long balance){
        this.balance = balance;
    }

    public String getAccountNumber() {
        return accountNumber;
    }

    public long getBalance() {
        return balance;
    }

    @Override
    public String toString() {
        return "{" + "accountNumber='" + accountNumber + '\'' + ", balance=" + balance + '}';
    }
}

핵심 포인트:

  • 객체의 상태를 직접 변경하지 않고, updateBalance() 메서드를 통해 수정하도록 구성함.
  • 이는 캡슐화(Encapsulation) 원칙을 지킨 좋은 예임.

② Service 계층 — 핵심 로직 구현

Service 계층은 입금(deposit)과 출금(withdraw)의 핵심 로직을 담당함.

이 로직은 BankServiceInterface 인터페이스를 통해 표준화되어 있음.

인터페이스 정의

package C04Interface.BankProgram;

public interface BankServiceInterface {
    void deposit(long money, BankAccount ba);
    boolean withdraw(long money, BankAccount ba);
}

이 인터페이스는 각기 다른 서비스(Kakao, Toss)가 동일한 규약으로 작동할 수 있도록
공통 기능 명세를 정의한 것임.


BankService (기본 서비스 클래스)

package C04Interface.BankProgram;

public class BankService {
    public void deposit(long money, BankAccount ba){
        long current = ba.getBalance();
        long newBalance = current + money;
        ba.updateBalance(newBalance);
    };

    public boolean withdraw(long money, BankAccount ba){
        long current = ba.getBalance();
        if(current < money){
            return false;
        } else {
            long newBalance = current - money;
            ba.updateBalance(newBalance);
            return true;
        }
    }
}
  • 입금(deposit): 현재 잔액(getBalance)에 입금 금액을 더함.
  • 출금(withdraw): 잔액 검증 후 차감, 가능 여부를 boolean으로 반환함.
  • 실제 비즈니스 로직의 기초 역할을 하는 클래스임.

BankKakaoService / BankTossService

두 클래스 모두 BankServiceInterface를 구현(implements)하며,
각 서비스별 로직을 동일한 규약으로 수행하도록 만든 것임.

package C04Interface.BankProgram;

public class BankKakaoService implements BankServiceInterface {

    public void deposit(long money, BankAccount ba){
        long current = ba.getBalance();
        long newBalance = current + money;
        ba.updateBalance(newBalance);
    };

    public boolean withdraw(long money, BankAccount ba){
        long current = ba.getBalance();
        if(current < money){
            return false;
        } else {
            long newBalance = current - money;
            ba.updateBalance(newBalance);
            return true;
        }
    }
}
package C04Interface.BankProgram;

public class BankTossService implements BankServiceInterface {

    public void deposit(long money, BankAccount ba){
        long current = ba.getBalance();
        long newBalance = current + money;
        ba.updateBalance(newBalance);
    };

    public boolean withdraw(long money, BankAccount ba){
        long current = ba.getBalance();
        if(current < money){
            return false;
        } else {
            long newBalance = current - money;
            ba.updateBalance(newBalance);
            return true;
        }
    }
}

BankKakaoService와 BankTossService는 내부 구현이 동일하지만,
실제 운영 환경에 따라 다르게 확장할 수 있는 구조적 유연성을 가짐.

예를 들어,

  • 카카오뱅크 API 연동,
  • Toss 결제 모듈 호출처럼 다른 시스템 로직으로 변경 가능함.

③ Controller 계층 — 사용자 인터페이스

컨트롤러는 사용자 입력을 받아 서비스 로직을 실행하게 하는 역할임.
입금, 출금 요청을 처리하며, 인터페이스를 기반으로 서비스 로직을 유연하게 교체할 수 있음.

package C04Interface.BankProgram;

import java.util.Scanner;

public class BankController {
    public static void main(String[] args) {

        System.out.println("계좌번호를 입력해주세요");
        Scanner sc = new Scanner(System.in);
        String accountNumber = sc.nextLine();

        BankAccount ba = new BankAccount(accountNumber, 0);
        BankServiceInterface bs = null;

        while (true) {
            System.out.println("입금하시려면 1번, 출금하시려면 2번");
            String serviceNumber = sc.nextLine();

            if (serviceNumber.equals("1")) {
                System.out.println("입금 방식을 선택해주세요. 1.카카오페이 2.토스페이");
                String number = sc.nextLine();
                System.out.println("입금하실 금액을 입력해주세요");
                long money = Long.parseLong(sc.nextLine());

                if (number.equals("1")) {
                    System.out.println("카카오 서비스 입니다.");
                    bs = new BankKakaoService();
                    bs.deposit(money, ba);

                } else if (number.equals("2")) {
                    System.out.println("토스 서비스 입니다.");
                    bs = new BankTossService();
                    bs.deposit(money, ba);
                }

            } else {
                System.out.println("출금하실 금액을 입력해주세요");
                long money = Long.parseLong(sc.nextLine());
                // 출금 로직은 구현 가능하게 남김
                // bs.withdraw(money, ba);
            }
        }
    }
}

컨트롤러 핵심 포인트

  • BankServiceInterface bs = null;
    → 인터페이스 타입으로 선언함으로써, 어떤 서비스 구현체든 유연하게 교체 가능함.

  • 사용자가 선택한 번호에 따라
    BankKakaoService 혹은 BankTossService 객체를 생성하여
    같은 방식으로 deposit() 호출이 가능함.

이 구조가 바로 다형성(Polymorphism) 의 대표적인 활용 예임.


전체 동작 구조 워크플로우

[사용자 입력]
     ↓
BankController (입금/출금 요청)
     ↓
BankServiceInterface (표준화된 인터페이스)
     ↓
BankKakaoService / BankTossService (구현체)
     ↓
BankAccount (엔티티 상태 업데이트)

핵심은 컨트롤러는 구체적인 서비스 구현체를 모르고도 동일한 로직을 실행할 수 있다는 점임.
이는 추후 새로운 결제수단(NaverPay, PaycoService)이 추가되어도
코드 변경 없이 확장할 수 있는 구조를 제공함.


정리

계층클래스역할
EntityBankAccount계좌번호와 잔액 등 상태 관리
Service InterfaceBankServiceInterface입출금의 규약 정의
Service ImplementationBankKakaoService, BankTossService입출금 로직 구체화
ControllerBankController사용자 입력/서비스 호출 관리

핵심 개념 요약

  • 인터페이스(interface) → 기능 명세 정의.
  • 구현체(implements) → 실제 로직 담당 클래스.
  • 다형성(polymorphism) → 하나의 인터페이스로 다양한 클래스 처리 가능함.
  • 계층 구조 설계 → 엔티티, 서비스, 컨트롤러로 역할 분리.
  • 확장성 확보 → 신규 서비스 추가 시 기존 코드 수정 없이 확장 가능함.
profile
Eazy하게

0개의 댓글