반응형
Notice
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- 알고리즘
- 컴퓨터비전
- 소프트웨어
- 소프트웨어공학
- 네트워크
- 프로그래밍언어
- 디자인패턴
- 클라우드컴퓨팅
- 데이터베이스
- 프로그래밍
- 딥러닝
- 웹개발
- 네트워크보안
- 데이터구조
- 컴퓨터과학
- 보안
- I'm Sorry
- 컴퓨터공학
- 자료구조
- 빅데이터
- 데이터분석
- 파이썬
- 버전관리
- 데이터과학
- 자바스크립트
- Yes
- 사이버보안
- 인공지능
- 머신러닝
- springboot
Archives
- Today
- Total
스택큐힙리스트
상속·다형성으로 ATM 시뮬레이터 확장 본문
반응형
목표 🔑
- 상속(Inheritance) 으로 계좌 타입 확장하기
- 다형성(Polymorphism) 으로 코드 의존도 낮추기
- ATM 시뮬레이터 구조 설계 & 구현
- OCP·LSP 같은 OOP 원칙 체감하기
1. 왜 ‘계좌’를 계층 구조로 나눌까?
은행 업무는 계좌 종류마다 규칙이 다릅니다. 예금·적금·마이너스통장 등 조건이 다른 로직을 하나의 클래스에 몰아넣으면 수정·추가 시마다 위험한 분기문이 폭증합니다.
- 상속 으로 공통 로직을 BankAccount 추상 클래스로 뽑아두면,
- 다형성 으로 SavingsAccount, CheckingAccount 를 하나의 타입으로 다룰 수 있어 확장성 과 가독성 이 모두 좋아집니다.
2. 기본 뼈대: 추상 클래스 & 인터페이스
public abstract class BankAccount {
protected String owner;
protected long balance;
public BankAccount(String owner, long balance) {
this.owner = owner;
this.balance = balance;
}
public void deposit(long amount) { balance += amount; }
public abstract void withdraw(long amount);
public long getBalance() { return balance; }
}
public interface Transferable {
void transfer(BankAccount target, long amount);
}
- 공통 로직(입금, 잔액 조회)은 추상 클래스에,
- 부가기능(계좌 간 이체)은 인터페이스로 분리 👉 필요 계좌만 구현.
3. 구현 계좌 클래스 — 규칙만 다르게!
// 자유입출금
public class CheckingAccount extends BankAccount implements Transferable {
public CheckingAccount(String owner, long balance) {
super(owner, balance);
}
@Override
public void withdraw(long amount) {
if (amount > balance) throw new IllegalStateException("잔액 부족");
balance -= amount;
}
@Override
public void transfer(BankAccount t, long amt) {
withdraw(amt);
t.deposit(amt);
}
}
// 적금(출금·이체 제한)
public class SavingsAccount extends BankAccount {
private final double interestRate = 0.03;
public SavingsAccount(String owner, long balance) {
super(owner, balance);
}
@Override
public void withdraw(long amount) {
throw new UnsupportedOperationException("적금은 중도 출금 불가");
}
public void addInterest() {
balance += (long) (balance * interestRate);
}
}
- 각 클래스는 필요한 부분만 오버라이딩 → OCP 만족
- 타입은 BankAccount 로 통일 → LSP·다형성 구현
4. ATM 시뮬레이터 핵심 로직
public class ATM {
private final Map<String, BankAccount> accounts = new HashMap<>();
public void register(BankAccount account) { accounts.put(account.owner, account); }
public void run() {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("[1]입금 [2]출금 [3]잔액 [4]이체 [0]종료");
int cmd = sc.nextInt(); // switch 문으로 제어
switch (cmd) {
case 1 -> depositFlow(sc);
case 2 -> withdrawFlow(sc);
case 3 -> balanceFlow(sc);
case 4 -> transferFlow(sc);
case 0 -> { System.out.println("안녕히 가세요!"); return; }
default -> System.out.println("잘못된 입력");
}
}
}
// ... 각 Flow 메서드는 계좌 객체를 다형적으로 사용
}
- UI(콘솔)와 비즈니스 로직 분리
- switch 문으로 메뉴 선택, 내부에서는 계좌 타입 구분 없이 동작
5. 확장 시 이점 ✨
- 새 상품(예: 외화통장) 추가 ⇒ 새 클래스를 extends BankAccount 로 한 줄만 등록
- 기존 ATM 코드는 수정 無 → OCP 실천
- 테스트 코드에서 List<BankAccount> 로 전체 케이스 순회 가능
- 스프링으로 전환 시 @Component 달아 DI 로 주입
6. 실습 체크리스트 ✔️
- 추상 클래스·인터페이스 선언
- SavingsAccount, CheckingAccount 각각 오버라이딩
- 다형성 활용: 리스트·맵에 BankAccount 타입으로 저장
- 예외 상황 JUnit5 테스트 작성
반응형
Comments