자바은행 - 상속 적용

프로그램에 새로운 요구 사항이 생겼다.
잔액이 음수여도 되는 계좌가 필요하다고 한다.
상속을 적용하면 기존 계좌를 슈퍼 클래스로, 잔액이 음수여도 되는 계좌를 서브 클래스로 둘 수 있다.
잔액이 음수가 가능한 계좌를 마이너스 계좌라고 부른다면, 마이너스 계좌는 슈퍼 클래스인 계좌 클래스의 출금 메소드인 withdraw()만 오버라이딩하면 된다.
은행 클래스의 계좌를 생성하는 메소드, addAccount(String accountNo, String name, double balance)는 생성할 계좌가 일반 계좌인지 마이너스 계좌인지를 판단해야 한다.
그러기 위해서는 파라미터가 추가로 필요하다.
kind 파라미터를 추가하고, 마이너스 계좌를 생성할 때 이 파라미터에 대시 (-) 문자를 넘기도록 한다.
마이너스 계좌 클래스를 MinusAccount로 이름 짓는다면 은행의 addAccount() 메소드는 다음과 같이 구현할 수 있다.

public void addAccount(String accountNo, String name, double balance, String kind) {
  Account account = this.getAccount(accountNo);
  if (account == null) {
    if (kind != null && kind.equals("-") {
      accounts.add(new MinusAccount(accountNo, name, balance));
    } else {
      accounts.add(new Account(accountNo, name, balance));
    } 
  }
}

상속을 적용하여 기존 예제를 수정한다.

Account.java
package net.java_school.bank;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Calendar;
import java.util.Date;

public class Account {
  private String accountNo;
  private String name;
  protected double balance;
  protected List<Transaction> transactions = new ArrayList<Transaction>();
    
  static final String KIND = "일반";//일반 계좌
  static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd");
  static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
  static final String DEPOSIT = "입금";
  static final String WITHDRAW = "출금";
  static final NumberFormat NUMBER_FORMAT = NumberFormat.getInstance();
  
  public Account() {}
  
  public Account(String accountNo, String name) {
    this.accountNo = accountNo;
    this.name = name;
  }
    
  public Account(String accountNo, String name, double balance) {
     this.accountNo = accountNo;
     this.name = name;
     this.balance = balance;
  }
    
  public void deposit(double amount) {
    balance = balance + amount;
    Transaction transaction = new Transaction();
    Calendar cal = Calendar.getInstance();
    Date date = cal.getTime();
    transaction.setTransactionDate(DATE_FORMAT.format(date));
    transaction.setTransactionTime(TIME_FORMAT.format(date));
    transaction.setAmount(amount);
    transaction.setBalance(balance);
    transaction.setKind(DEPOSIT);
    transactions.add(transaction);
  }
    
  public void withdraw(double amount) {
    if (amount > balance) {
      return;
    }
    balance = balance - amount;
    Transaction transaction = new Transaction();
    Calendar cal = Calendar.getInstance();
    Date date = cal.getTime();
    transaction.setTransactionDate(DATE_FORMAT.format(date));
    transaction.setTransactionTime(TIME_FORMAT.format(date));
    transaction.setAmount(amount);
    transaction.setBalance(balance);
    transaction.setKind(WITHDRAW);
    transactions.add(transaction);
  }
    
  public String getName() {
    return name;
  }
    
  public void setName(String name) {
    this.name = name;
  }
    
  public String getAccountNo() {
    return accountNo;
  }
    
  public void setAccountNo(String accountNo) {
    this.accountNo = accountNo;
  }
    
  public double getBalance() {
    return balance;
  }
    
  public void setBalance(double balance) {
    this.balance = balance;
  }
    
  public List<Transaction> getTransactions() {
    return transactions;
  }
    
  public void setTransactions(List<Transaction> transactions) {
    this.transactions = transactions;
  }

  public String getKind() {
    return KIND;
  }
    
  @Override
  public String toString() {
    StringBuffer sb = new StringBuffer();
    sb.append(accountNo);
    sb.append("|");         
    sb.append(name);
    sb.append("|");
    sb.append(NUMBER_FORMAT.format(balance));
    sb.append("|");
    sb.append(getKind());
                
    return sb.toString();
  }

}

거래내용 클래스는 toString() 메소드의 강조된 부분만 변경한다.

@Override
public String toString() {
  StringBuilder sb = new StringBuilder();
  sb.append(this.transactionDate);
  sb.append("|");
  sb.append(this.transactionTime);
  sb.append("|");
  sb.append(this.kind);
  sb.append("|");
  sb.append(Account.NUMBER_FORMAT.format(amount));
  sb.append("|");
  sb.append(Account.NUMBER_FORMAT.format(balance));
  
  return sb.toString();
}

다음은 마이너스 계좌 클래스다.

package net.java_school.bank;

import java.util.Calendar;
import java.util.Date;

public class MinusAccount extends Account {
  static final String KIND = "마이너스";//마이너스 계좌

  public MinusAccount() {}

  public MinusAccount(String accountNo, String name) {
    super(accountNo, name);
  }

  public MinusAccount(String accountNo, String name, double balance) {
    super(accountNo, name, balance);
  }
    
  @Override
  public String getKind() {
    return KIND;
  }

  public void withdraw(double amount) {
    balance = balance - amount;
    Transaction transaction = new Transaction();
    Calendar cal = Calendar.getInstance();
    Date date = cal.getTime();
    transaction.setTransactionDate(Account.DATE_FORMAT.format(date));
    transaction.setTransactionTime(Account.TIME_FORMAT.format(date));
    transaction.setAmount(amount);
    transaction.setBalance(balance);
    transaction.setKind(Account.WITHDRAW);
    transactions.add(transaction);
  }
        
}

다음은 은행 클래스다.

package net.java_school.bank;

import java.util.ArrayList;

public class Bank {
  private List<Account> accounts = new ArrayList<Account>();

  public void addAccount(String accountNo, String name) {
    Account account = this.getAccount(accountNo);
    if (account == null) {
      accounts.add(new Account(accountNo, name));
    }
  }
    
  public void addAccount(String accountNo, String name, double balance) {
    Account account = this.getAccount(accountNo);
    if (account == null) {
      accounts.add(new Account(accountNo, name, balance));
    }
  }

  public void addAccount(String accountNo, String name, String kind) {
    Account account = this.getAccount(accountNo);
    if (account == null) {
      if (kind != null && kind.equals("-")) {
        accounts.add(new MinusAccount(accountNo, name));
      } else {
        accounts.add(new Account(accountNo, name));
      }
    }
  }
    
  public void addAccount(String accountNo, String name, double balance, String kind) {
    Account account = this.getAccount(accountNo);
    if (account == null) {
      if (kind != null && kind.equals("-")) {
        accounts.add(new MinusAccount(accountNo, name, balance));
      } else {
        accounts.add(new Account(accountNo, name, balance));
      }
    }
  }
    
  public Account getAccount(String accountNo) {
    int totalAccount = accounts.size();
    for (int i = 0; i < totalAccount; i++) {
      if (accountNo.equals(accounts.get(i).getAccountNo())) {
        return accounts.get(i);
      }
    }
    return null;
  }
    
  public List<Account> findAccountByName(String name) {
    List<Account> matched = new ArrayList<Account>();
    int size = accounts.size();
    for (int i = 0; i < size; i++) {
      if (name.equals(accounts.get(i).getName())) {
        matched.add(accounts.get(i));
      }
    }
        
    return matched;
  }
    
  public List<Account> getAccounts() {
    return accounts;
  }
  
}

테스트 클래스에 강조된 부분을 추가한 후 실행한다.

package net.java_school.bank;

import java.util.List;

public class Test {
  static final String ACCOUNTS_HEADING = "계좌번호|소유자명|잔액|계좌종류";
  static final String TRANSACTIONS_HEADING = "거래일|거래시간|입/출금|거래금액|잔액";

  public static void main(String[] args) {

    //테스트 계좌를 추가한다..
    Bank bank = new Bank();
    bank.addAccount("101", "홍길동");
    bank.addAccount("202", "임꺽정");
    bank.addAccount("303", "장길산");
    bank.addAccount("404", "홍길동", "-");
        
    //..생략..

    System.out.println();

    //6. 마이너스 계좌 404에서 5000원을 출금한다.
    System.out.println("6. 마이너스 계좌 404에서 5000원을 출금한다.");
    Account minus = bank.getAccount("404");
    minus.withdraw(5000);
    System.out.println(ACCOUNTS_HEADING);
    System.out.println(minus);
  }

}
6. 마이너스 계좌 404에서 5000원을 출금한다.
계좌번호|소유자명|잔액|계좌종류
404|홍길동|-5,000|마이너스

다음 예외 클래스를 만들어서 적용해 보자.

  • 중복된 계좌 - DuplicateAccountException
  • 잔액부족 - InsufficientBalanceException
참고
  • New 알기쉬운 자바2(개정판) 저자: 김철회 출판사: 정보문화사