classHeatingPlan {withinRange(bottom, top) {return (bottom >=this._temperatureRange.low && top >=this._temperatureRange.high); }}constlow=aRoom.daysTempRange.low;consthigh=aRoom.daysTempRange.high;if (!aPlan.withinRange(low, high)) { alerts.push('방 온도가 지정 범위를 벗어났습니다.'); }
After
classHeatingPlan {withinRange(aNumberRange) {return (aNumberRange.low >=this._temperatureRange.low &&aNumberRange.high >=this._temperatureRange.high); }}if (!aPlan.withinRange(aRoom.daysTempRange)) { alerts.push('방 온도가 지정 범위를 벗어났습니다.'); }
절차
매개변수들을 원하는 형태로 받는 빈 함수 만들기
새 함수의 본문은 원래 함수를 호출하고, 새 매개변수와 원래 함수의 매개변수를 매핑
정적 검사 수행
새 함수를 호출하도록 수정
원래 함수를 인라인
새 함수의 이름을 적절히 수정하고 모든 호출자에 반영
참고. 추출과 인라인 리팩터링을 이용한 방법
classHeatingPlan {xxNEWwithinRange(tempRange) { // 함수 추출하기constlow=tempRange.low; // 입력 매개변수 추출하기consthigh=tempRange.high;constisWithinRange=this.withinRange(low, high);return isWithinRange; }withinRange(bottom, top) {return (bottom >=this._temperatureRange.low && top >=this._temperatureRange.high); }}consttempRange=aRoom.daysTempRange;constisWithinRange=aPlan.xxNEWwithinRange(tempRange);if (!isWithinRange) {alerts.push('방 온도가 지정 범위를 벗어났습니다.');}
let totalAscent =0;calculateAscent();functioncalculateAscent() {for (let i =1; i <points.length; i++) {constverticalChange= points[i].elevation - points[i -1].elevation; totalAscent += verticalChange >0? verticalChange :0; }}
After
consttotalAscent=calculateAscent(); //.1, 3functioncalculateAscent() { //.4let result =0; //.2for (let i =1; i <points.length; i++) {constverticalChange= points[i].elevation - points[i -1].elevation; result += verticalChange >0? verticalChange :0; }return result; //.1}
절차 (매 단계 테스트)
호출자는 함수가 반환하는 수정된 값을 자신의 변수에 저장하기
피호출 함수 안에 반환할 값을 가리키는 새로운 변수 선언하기
계산이 선언과 동시에 이루어지도록 통합하기 (+변수를 불변으로 만들기)
피호출 함수의 변수 이름을 새 역할에 어울리도록 수정하기
오류 코드를 예외로 바꾸기
예외는 프로그래밍 언어에서 제공하는 독립적인 오류 처리 메커니즘이다.
예외를 사용하면 오류 코드를 일일이 검사하거나 오류를 식별해 콜스택 위로 던지는 일을 신경쓰지 않아도 된다.
예외는 정확히 예상 밖의 동작일 때만 쓰자.
개요
Before
if (data) returnnewShippingRules(data);elsereturn-23;
After
if (data)returnnewShippingRules(data);elsethrownewOrderProcessingError(-23);
절차 (매 단계 테스트)
콜스택 상위에 해당 예외를 처리할 예외 핸들러 작성하기
해당 오류 코드를 대체할 예외와 그 밖의 예외를 구분할 식별 방법 찾기
예외를 클래스 기반으로 처리할 수 있다면 서브클래스 만들기
정적 검사 수행하기
catch절을 수정하여 직접 처리할 수 있는 예외는 적절히 대처하고, 그렇지 않은 예외는 다시 던지기
오류 코드를 반환하는 곳 모두에서 예외를 던지도록 수정하기
오류 코드를 콜스택 위로 전달하는 코드 모두 제거하기
Example
classOrderProcessingErrorextendsError { // 2. 예외를 클래스 기반으로 처리constructor(errorCode) {super(`주문 처리 오류 ${errorCode}`);this.code = errorCode; }getname() { return'OrderProcessingError'; }}functionlocalShippingRules(country) {constdata=countryData.shippingRules[country];if (data) returnnewShippingRules(data);elsethrownewOrderProcessingError(-23); // 5. 오류 코드 대신 예외 클래스 사용}functioncalculateShippingCosts(anOrder) {constshippingRules=localShippingRules(anOrder.country);// ...}try { // 1. 예외 핸들러 작성하기calculateShippingCosts(orderData);} catch (e) {if (e instanceofOrderProcessingError) // 4. 예외 클래스를 처리errorList.push({order: orderData, errorCode:e.code,});elsethrow e;}
예외를 사전확인으로 바꾸기
예외는 '뜻밖의 오류'라는 말 그대로 예외적인 동작에만 사용하자.
함수 수행 시 문제가 될 수 있는 조건을 함수 호출 전에 검사하자.
예외를 던지는 대신 호출하는 곳에서 조건을 검사하도록 해보자.
개요
Before
privateDeque<Resource> avaliable;privateList<Resource> allocated;publicResourcePoolget() {Resource result;try { result =avaliable.pop()allocated.add(result); } catch (NoSuchElementException e) { result =Resource.create();allocated.add(result) }return result;}
After
privateDeque<Resource> available;privateList<Resource> allocated;publicResourcePoolget() {// 조건 검사 코드 (try, catch 문을 조건절로 이동)Resource result =available.isEmpty() ?Resource.create() :available.pop()allocated.add(result);return result;}