✏️1.9 상태 점검: 다형성을 활용하여 데이터 생성하기

❓다형성을 추가한 결과 무엇이 달라졌을까

결과

export default function createStatementData(invoice, plays) {
  const result = {};
  result.customer = invoice.customer; 
  result.performances = invoice.performances.map(enrichPerformance);
  result.totalAmount = totalAmount(result);	
  result.totalVolumeCredits = totalVolumeCredits(result);
  return result;
  
function enrichPerformance(aPerformance) {
  const calculator = createPerformanceCalculator(aPerformance, playFor(aPerformance));   // 생성자 대신 팩터리 함수 이용
  const result = Object.assign({}, aPerformance); 
  result.play = calculator.play;
  result.amount = calculator.amount;  
  result.volumeCredits = calculator.volumeCredits;
  return result;
}

function playFor(aPerformance) {
  return plays[aPerformance.playID]
}
   
function totalAmount(data) {
  return data.performances 
    .reduce((total, p) => total + p.amount, 0);
}
function totalVolumeCredits(data) {
  return data.performances
    .reduce((total, p) => total + p.volumeCredits, 0); 

function createPerformanceCalculator(aPerformance, aPlay) {
  switch(aPlay.type) {
  case "tragedy": return new TragedyCalculator(aPerformance, aPlay);
  case "comedy": return new ComedyCalculator(aPerformance, aPlay);
  default:
    throw new Error(`알 수 없는 장르: ${aPlay.type}`);
  }
}

class PerformanceCalculator {   
  constructor(aPerformance, aPlay) {
    this.performance = aPerformance;
    this.play = aPlay;
  }
  
  get amount() {
    throw new Error('서브클래스에서 처리하도록 설계되었습니다.');
  }
  
  get volumeCredits() {
    return Math.max(this.performance.audience - 30, 0);
  }
}

class TragedyCalculator extends PerformancesCalculator {
  get amount () {
    let result = 40000;
    if (this.performance.audience > 30) {
      result += 1000 * (this.performance.audience - 30);
    }
    return result;
  }
}

class ComedyCalculator extends PerformanceCalculator {
  get amount() {
    let result = 30000;
    if (this.performance.audience > 20) {
      result += 1000 + 500 * (this.performance.audience - 20);
    }
    return result;
  }
  
  get volumeCredits() {
    return super.volumeCredits + Math.floor(this.performance.audience / 5);
  }
}

연극 장르별 계산 코드들을 함께 묶어뒀다. 새로운 장르를 추가하려면 해당 자르의 서브클래스를 작성하고 생성 함수인 createPerformanceCalculator()에 추가하기만 하면 된다.

두 개의 함수 amountFor()volumeCreditsFor()의 조건부 로직을 생성 함수 하나로 옮겼다. 같은 타입의 다형성을 기반으로 실행되는 함수가 많을 수록 이렇게 구성하는 것이 유리하다.

이 코드는 서브 클래스를 언제 사용하면 좋은지에 대한 예이기도 하다.

Last updated