본문 바로가기

TIL

This Week. 2.1 ~ 2.6

이번 주는 리팩터링만 읽은 거 같다. 알고리즘들을 조금씩 풀고 있기는 한데, 기본적인 문제들을 다시 보는 중이다. 오늘은 타입 스크립트 복습도 하고 리팩터링도 복습할 겸 리팩터링 예시 코드를 타입 스크립트로 바꿔봤다. 막상 개념적으로 알고 있던 것들 바꾸려니까 익숙하지가 않아서 힘들었다. 특히 객체들 타입 정하는 게 생각보다 깔끔하게 하기가 힘들다. 실제로 실무에서는 밑에 처럼 하면 안 될 텐데 어떤 식으로 타입들을 작성해야 깔끔한지 아직 잘 감이 안 온다. 다른 코드들 좀 많이 봐야겠다. 기존 코드는 https://kspsd.tistory.com/103  여기에 있다.

import type {play,playValue} from "./plays.js"
import type {performance ,invoice} from "./invoices.js"
//import 'core-js';

type resPerf={
    play?:playValue
    amount?:number
    volumeCredits?:number
} & performance
type res ={
    customer?:string,
    performances?:resPerf[],
    totalAmount?:number,
    totalVolumeCredits?:number
   
}

class PerformanceCalculator {
    performance: performance;
    play: playValue;

    constructor(aPerformance: performance, aPlay:playValue) {
        this.performance = aPerformance;
        this.play = aPlay;

    }
    getamount() {
        throw new Error("서브 클래스에서 처리하도록 설계되었습니다.")
    }
    getvolumeCredits():number {

        return Math.max(this.performance.audience - 30, 0);

    }
}

class TragedyCalculator extends PerformanceCalculator {
    result: number;
    constructor(aPerformance: performance, aPlay:playValue){
        super(aPerformance,aPlay)
    }
    getamount() {
        let result = 40000;
        if (this.performance.audience > 30) {
            result += 1000 * (this.performance.audience - 30);
        }
        return result
    }
}
class ComedyCalculator extends PerformanceCalculator {
    result: number;

    constructor(aPerformance: performance, aPlay:playValue){
        super(aPerformance,aPlay)
    }
    getamount():number {
        let result = 30000;
        if (this.performance.audience > 20) {
            result += 10000 + 500 * (this.performance.audience - 20);
        }
        result += 300 * this.performance.audience;
        return result
    }
    getvolumeCredits():number {

        return super.getvolumeCredits()+Math.floor(this.performance.audience /5);

    }
}




export default function createStatementData(invoice:invoice, plays:play) :res {
    
    const result:res = {};
    result.customer = invoice.customer;
    result.performances = invoice.performances.map(enrichPerformance);
    result.totalAmount = totalAmount(result);
    result.totalVolumeCredits = totalVolumeCredits(result);

    return result

    function enrichPerformance(aPerformance:resPerf):resPerf {
        const calculator = createPerformanceCalculator(aPerformance, playFor(aPerformance));
        const result = {...aPerformance}; //얕은 복사 수행
        result.play = calculator.play
        result.amount = calculator.getamount();
        result.volumeCredits = calculator.getvolumeCredits();
        return result
    }

    function playFor(aPerformance:performance):playValue {
        return plays[aPerformance.playID]
    }

    // function amountFor(aPerformance) {
    //     return new PerformanceCalculator(aPerformance, aPerformance.play).getamount()
    // }


    // function volumeCreditsFor(aPerformance) {
    //     return new PerformanceCalculator(aPerformance, aPerformance.play).getvolumeCredits()
    // }


    function totalAmount(data:res):number {
        return data.performances.reduce((total, p) => total + p.amount, 0)
    }

    function totalVolumeCredits(data:res):number {
        return data.performances.reduce((total, p) => total + p.volumeCredits, 0)
    }

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

위에는  createStatementData 모듈 코드다.  statement 모듈은 비교적 추가할게 적어서 따로 올리지는 않았다. 원래 getter함수들을 사용했는데, 찾아보니까 타입스크립트 쓸 때는 헷갈려서 그냥 함수로 작성한다는 글을 봤다. 그래서 일반 함수로 값을 가져오게 변경했고, 내가 아직 자바스크립트로 작성을 많이 안해봐서  class 상속 구조 코드 바꾸는데도 많이 헷갈렸다. 그리고 위에 resPerf 함수를 교차 타입으로 합쳐서 표현했는데, 그냥 예시 코드를 바꾸는거여서 의도에 따라 달라지긴 하겠지만 다른 방식으로 더 깔끔하게 만들 수 있지 않을까.  아 그리고 원래 얕은 복사 수행할 때 

위처럼 작성했는데, 자꾸 컴파일할 때 에러가 나서 tsconfig에  target도 넣어보고 lib 에다가도 추가해 주고 해 봤는데 안돼서 그냥 다른 방식으로 복사해 주었다. 또 리팩터링 기법 중에 중간에 데이터 구조를 만들 때 코드처럼 타입을 저런 식으로 만드는 게 맞는지 모르겠다. 

그냥 타입스크립트 개념만 보고 할 때랑 확실히 코드를 바꿔보면서 해보니까 훨씬 재밌었다. 근데 위에서 처럼 아직 코드를 많이 안 봐서 일단은 다른 코드들을 많이 보고 다시 작성해봐야겠다.