개요

함수는 기본적인 빌딩 블록

함수를 함수만을 위한 객체로 캡슐화하면 유용해질 있다.

이런 객체를 "명령 객체(command object)" 혹은 "명령(command)"이라 한다.

명령 객체는 대게 메서드 하나로 구성된다.

 

명령은 함수보다 유연하다. 되돌리기 기능같은 보조 연산을 제공할 있다.

객체를 지원하지만 일급 함수를 지원하지 않은 언어에서 명령을 이용해 일급 함수의 기능 대부분을 흉내 있다.

마찬가지로 중첩 함수를 지원하지 않는 언어에서도 이를 이용해 복잡한 함수를 잘게 쪼갤 있다. 잘게 쪼갤 수록 디버깅이 쉬워진다.

 

명령 리팩터링은 유연성을 얻는 대신 복잡성이 증가한다. 따라서 적용할 대상을 신중히 선택해야 한다.

 

일급 함수를 지원하는 언어에서는 대부분 명령 대신 일급 함수를 사용한다

 

예시

건강보험 점수 계산 함수



function score(candidate, medicalExam, scoringGuide){
    let result = 0;
    let healthLevel = 0;
    let highMedicalRiskFlag = false;
    if(medicalExam.isSmoker){
        healthLevel += 10;
        highMedicalRiskFlag =true;
    }
    let certificationGrade = "regular";
    if(scoringGuide.stateWithLowCertification(candidate.originState)){
        certificationGrade = "low";
        result -= 5;
    }
    //많은 코드...
    result -= Math.max(healthLevel -5 , 0);
    return result;
}


function score(candidate, medicalExam, scoringGuide){
    return new Score().execute(candidate,medicalExam,scoringGuide);
}
//클래스를 만들고 함수 옮기기
class Score{
    execute(candidate,medicalExam, scoringGuide){
        let result = 0;
        let healthLevel = 0;
        let highMedicalRiskFlag = false;
   
        if(medicalExam.isSmoker){
            healthLevel += 10;
            highMedicalRiskFlag =true;
        }
        let certificationGrade = "regular";
        if(scoringGuide.stateWithLowCertification(candidate.originState)){
            certificationGrade = "low";
            result -= 5;
        }
        //많은 코드...
        result -= Math.max(healthLevel -5 , 0);
        return result;
    }
}
명령 객체로 바꿀 함수 매개변수를 최대한 생성자로 옮겨 매개변수 목록을 줄이는 것이 좋다. 가장 좋은 것은 없는 것이다.


function score(candidate, medicalExam, scoringGuide){
    return new Score(candidate).execute(medicalExam,scoringGuide);
}
//명령 매개변수 최대한 생성자로 옮기기
class Score{
    constructor(candidate){
        this._candidate = candidate;
    }
    execute(medicalExam, scoringGuide){
        let result = 0;
        let healthLevel = 0;
        let highMedicalRiskFlag = false;
   
        if(medicalExam.isSmoker){
            healthLevel += 10;
            highMedicalRiskFlag =true;
        }
        let certificationGrade = "regular";
        if(scoringGuide.stateWithLowCertification(candidate.originState)){
            certificationGrade = "low";
            result -= 5;
        }
        //많은 코드...
        result -= Math.max(healthLevel -5 , 0);
        return result;
    }
}


function score(candidate, medicalExam, scoringGuide){
    return new Score(candidate,medicalExam,scoringGuide).execute();
}
//명령 매개변수 최대한 생성자로 옮기기
class Score{
    constructor(candidate,medicalExam,scoringGuide){
        this._candidate = candidate;
        this._medicalExam = medicalExam;
        this._scoringGuide = scoringGuide;
    }
    execute(){
        let result = 0;
        let healthLevel = 0;
        let highMedicalRiskFlag = false;
   
        if(this._medicalExam.isSmoker){
            healthLevel += 10;
            highMedicalRiskFlag =true;
        }
        let certificationGrade = "regular";
        if(this._scoringGuide.stateWithLowCertification(this._candidate.originState)){
            certificationGrade = "low";
            result -= 5;
        }
        //많은 코드...
        result -= Math.max(healthLevel -5 , 0);
        return result;
    }
}

 

가다름기

명령으로 바꾼 주된 목적은 복잡한 함수를 잘게 나누는 것에 있다.

먼저 모든 지역 변수를 필드로 변경



class Score{
    constructor(candidate,medicalExam,scoringGuide){
        this._candidate = candidate;
        this._medicalExam = medicalExam;
        this._scoringGuide = scoringGuide;
    }
    //더 가다듬기, 명령의 목적인 복잡한 함수를 잘게 쪼게기 시작
    execute(){
        this._result = 0;
        this._healthLevel = 0;
        this._highMedicalRiskFlag = false;
   
        if(this._medicalExam.isSmoker){
            this._healthLevel += 10;
            this._highMedicalRiskFlag =true;
        }
        let certificationGrade = "regular";
        if(this._scoringGuide.stateWithLowCertification(this._candidate.originState)){
            certificationGrade = "low";
            this._result -= 5;
        }
        //많은 코드...
        this._result -= Math.max(this._healthLevel -5 , 0);
        return result;
    }
}
함수가 사용하던 로컬 변수를 필드로 바꾸면, 변수를 자유롭게 접근할 있어 다른 리팩터링이 수월해진다.


function score(candidate, medicalExam, scoringGuide){
    return new Score(candidate,medicalExam,scoringGuide).execute();
}
class Score{
    constructor(candidate,medicalExam,scoringGuide){
        this._candidate = candidate;
        this._medicalExam = medicalExam;
        this._scoringGuide = scoringGuide;
    }
    execute(){
        this._result = 0;
        this._healthLevel = 0;
        this._highMedicalRiskFlag = false;
   
        this.scoreSmoking();
        let certificationGrade = "regular";
        if(this._scoringGuide.stateWithLowCertification(this._candidate.originState)){
            certificationGrade = "low";
            this._result -= 5;
        }
        //많은 코드...
        this._result -= Math.max(this._healthLevel -5 , 0);
        return result;
    }
    //이렇게 쪼게놓으면 디버깅이 훨씬 쉬워진다.(디버깅 포인트가 더욱 촘촘해짐)
    scoreSmoking() {
        if (this._medicalExam.isSmoker) {
            this._healthLevel += 10;
            this._highMedicalRiskFlag = true;
        }
    }
}

 

 

+ Recent posts