개요

좋은 소프트웨어 설계 핵심은 모듈화 수준이다.

모듈성이란 프로그램 어딘가를 수정 해당 기능과 관련된 극히 작은 부분만 이해 해도되는 능력이다.

 

모듈성이 높으려면 연관된 요소를 하나의 요소로 묶고, 요소 사이 연결 관계를 쉽게 이해할 있어야 한다.

 

객체 지향 프로그래밍의 핵심 모듈화 컨텍스트는 클래스다.

 

A 함수가 자신이 속한 모듈보다 다른 모듈을 참조한다면 옮겨야한다.

 

예시: 중첩 함수를 최상위로 옮기기

 



/* GPS 추적 기록의 총 거리를 계산하는 함수 */
function trackSummary(points){
    const totalTime = calculateTime();
    const totalDistance = calculateDistance();
    const pace = totalTime / 60 / totalDistance;
    return {
        time : totalTime,
        distance : totalDistance,
        pace : pace,
    };
    function calculateDistance() { //총 거리 계산
        let result = 0;
        for(let i = 1; i < points.length ; i++){
            result += distance(points[i-1], points[i]);
        }
        return result;
    }
    function distance(p1, p2) {/* 두 지점의 거리 계산 */}
    function radians(degrees) {/* 라디안값으로 변환 */}
    function calculateTime() {/* 총 시간 계산 */}
}
중첩 함수 calculateDistance() 최상위로 옮겨서 다른 정보와 독립적으로 계산하고 싶다.


function trackSummary(points){
    const totalTime = calculateTime();
    const totalDistance = calculateDistance();
    const pace = totalTime / 60 / totalDistance;
    return {
        time : totalTime,
        distance : totalDistance,
        pace : pace,
    };
    function calculateDistance() { //총 거리 계산
        let result = 0;
        for(let i = 1; i < points.length ; i++){
            result += distance(points[i-1], points[i]);
        }
        return result;
    }
    function distance(p1, p2) {/* 두 지점의 거리 계산 */}
    function radians(degrees) {/* 라디안값으로 변환 */}
    function calculateTime() {/* 총 시간 계산 */}
}
function top_calculateDistance() { //최상위로 복사,임시이름
    let result = 0;
    for(let i = 1; i < points.length ; i++){
        result += distance(points[i-1], points[i]);
    }
    return result;
}


function trackSummary(points){
    const totalTime = calculateTime();
    const totalDistance = calculateDistance();
    const pace = totalTime / 60 / totalDistance;
    return {
        time : totalTime,
        distance : totalDistance,
        pace : pace,
    };
    function calculateDistance() { //총 거리 계산
        let result = 0;
        for(let i = 1; i < points.length ; i++){
            result += distance(points[i-1], points[i]);
        }
        return result;
        //distance, radians 는 현재 문맥에서 calculateDistance에서만 사용중
        //따라서 calculateDistance()함수 안으로 옮기는게 적절하다.
        function distance(p1, p2) {
            const EARTH_RADIUS = 3959; // 단위 마일
            const dLat = radians(p2.lat) - radians(p1.lat);
            const dLon = radians(p2.lon) - radians(p1.lon);
            const a = Math.pow(Math.sin(dLat / 2), 2)
                + Math.cos(radians(p2.lat))
                * Math.cos(radians(p1.lat))
                * Math.pow(Math.sin(dLon /2), 2);
            const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
            return EARTH_RADIUS * c;
        }
        function radians(degrees) {
            return degrees * Math.PI / 180;
        }
    }
    function calculateTime() {/* 총 시간 계산 */}
}
function top_calculateDistance(points) {
    let result = 0;
    for(let i = 1; i < points.length ; i++){
        result += distance(points[i-1], points[i]);
    }
    return result;
}


function top_calculateDistance(points) {
    let result = 0;
    for(let i = 1; i < points.length ; i++){
        result += distance(points[i-1], points[i]);
    }
    return result;
    //top_calculateDistance()함수도 똑같이 옮겨준다.
    function distance(p1, p2) {
        const EARTH_RADIUS = 3959; // 단위 마일
        const dLat = radians(p2.lat) - radians(p1.lat);
        const dLon = radians(p2.lon) - radians(p1.lon);
        const a = Math.pow(Math.sin(dLat / 2), 2)
            + Math.cos(radians(p2.lat))
            * Math.cos(radians(p1.lat))
            * Math.pow(Math.sin(dLon /2), 2);
        const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
        return EARTH_RADIUS * c;
    }
    function radians(degrees) {
        return degrees * Math.PI / 180;
    }
}


function trackSummary(points){
    const totalTime = calculateTime();
    const totalDistance = calculateDistance();
    const pace = totalTime / 60 / totalDistance;
    return {
        time : totalTime,
        distance : totalDistance,
        pace : pace,
    };
    //복사 함수를 호출하도록 수정한다.
    function calculateDistance() { //총 거리 계산
        return top_calculateDistance(points);
    }
    function calculateTime() {/* 총 시간 계산 */}
}
시점에서 반드시 테스트를 정상 동작을 확인한다.
정상 동작한다면 기존 함수 제거 복사 함수를 직접 호출하도록 수정한다.
function trackSummary(points){
    const totalTime = calculateTime();
    const totalDistance = top_calculateDistance();
    const pace = totalTime / 60 / totalDistance;
    return {
        time : totalTime,
        distance : totalDistance,
        pace : pace,
    };
    function calculateTime() {/* 총 시간 계산 */}
}


function trackSummary(points){
    const totalTime = calculateTime();
    const pace = totalTime / 60 / totalDistance();
    return {//적절한 이름으로 변경 후 인라인
        time : totalTime,
        distance : totalDistance(),
        pace : pace,
    };
    function calculateTime() {/* 총 시간 계산 */}
}


function trackSummary(points){
    const totalTime = calculateTime();
    const pace = totalTime / 60 / totalDistance();
    return {
        time : totalTime,
        distance : totalDistance(),
        pace : pace,
    };
    function calculateTime() {/* 총 시간 계산 */}
}
function totalDistance(points) {
    let result = 0;
    for(let i = 1; i < points.length ; i++){
        result += distance(points[i-1], points[i]);
    }
    return result;
}
//distance, radians totalDistance안에 어떤 것도 의존하지 않으니
//최상단으로 옮겼다.
function distance(p1, p2) {
    const EARTH_RADIUS = 3959; // 단위 마일
    const dLat = radians(p2.lat) - radians(p1.lat);
    const dLon = radians(p2.lon) - radians(p1.lon);
    const a = Math.pow(Math.sin(dLat / 2), 2)
        + Math.cos(radians(p2.lat))
        * Math.cos(radians(p1.lat))
        * Math.pow(Math.sin(dLon /2), 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    return EARTH_RADIUS * c;
}
function radians(degrees) {
    return degrees * Math.PI / 180;
}

 

예시: 다른 클래스로 옮기기



class Account{
    get bankCharge(){ //은행이자
        let result = 4.5;
        if(this._daysOverdrawn > 0) result += this.overdraftCharge;
        return result
    }
    get overdraftCharge(){
        if(this.type.isPremium){//초과 인출 이자 계산
            const baseCharge = 10;
            if(this.daysOverdrawn <= 7){
                return baseCharge;
            }else{
                return baseCharge + (this.daysOverdrawn - 7) * 0.85;
            }
        }else{
            return this.daysOverdrawn * 1.75;
        }
    }
}
계좌 종류에 따라 이자 책정 알고리즘이 달라지도록 수정


class AccountType{
    //계좌 타입으로 복사 후 적절하게 수정
    //daysOverdrawn는 계좌별로 달라지므로 원래 클래스에 남겨두었다.
    overdraftCharge(daysOverdrawn){
        if(this.isPremium){
            const baseCharge = 10;
            if(this.daysOverdrawn <= 7){
                return baseCharge;
            }else{
                return baseCharge + (daysOverdrawn - 7) * 0.85;
            }
        }else{
            return daysOverdrawn * 1.75;
        }
    }
}


class Account{
    get bankCharge(){
        let result = 4.5;
        if(this._daysOverdrawn > 0) result += this.overdraftCharge;
        return result
    }
    get overdraftCharge(){//위임 메서드
        return this.type.overdraftCharge(this.daysOverdrawn);
    }
}
class AccountType{
    overdraftCharge(daysOverdrawn){
        if(this.isPremium){
            const baseCharge = 10;
            if(this.daysOverdrawn <= 7){
                return baseCharge;
            }else{
                return baseCharge + (daysOverdrawn - 7) * 0.85;
            }
        }else{
            return daysOverdrawn * 1.75;
        }
    }
}


class Account{
    get bankCharge(){
        let result = 4.5;
        if(this._daysOverdrawn > 0)
            //인라인할지 고민한 결과 인라인하기로 결정
            result += this.type.overdraftCharge(this.daysOverdrawn);
        return result
    }
}
class AccountType{
    overdraftCharge(daysOverdrawn){
        if(this.isPremium){
            const baseCharge = 10;
            if(this.daysOverdrawn <= 7){
                return baseCharge;
            }else{
                return baseCharge + (daysOverdrawn - 7) * 0.85;
            }
        }else{
            return daysOverdrawn * 1.75;
        }
    }
}

 

 

 

+ Recent posts