자바스크립트같은동적타입언어라면앞에타입을명시하는식으로이름짓는것도좋다. (String name ==> let strName)
예시
가장간단한바꾸기는유효범위가좁은변수다.
let tpHd = "untitled"; //참조하는 곳 result += `<h1>${tpHd}</h1>`; obj['articleTitle'] = 'Hello World'; //바꾸는 곳 tpHd = obj['articleTitle'];
let tpHd = "untitled"; result += `<h1>${title()}</h1>`; obj['articleTitle'] = 'Hello World'; setTitle(obj['articleTitle']); //캡슐화 //게터 function title(){ return tpHd;} //세터 function setTitle(arg){tpHd = arg;}
let 이제변수이름바꿔도됨 = "untitled"; result += `<h1>${title()}</h1>`; obj['articleTitle'] = 'Hello World'; setTitle(obj['articleTitle']); function title(){ return 이제변수이름바꿔도됨;} function setTitle(arg){이제변수이름바꿔도됨 = arg;}
이름변경후다시함수를인라인해도된다. 단, 캡슐화한변수가전역으로두루사용된다면, 나중을위해함수로두는것이더좋다.
예시:상수이름바꾸기
상수의이름은캡슐화하지않고복제방식으로점진적으로바꿀수있다.
const cpyNm = "애크미 구스베리";
//원본 이름 바꾼 후 이전 원본 이름에 바꾼 이름 복제본 대입 const companyName = "애크미 구스베리"; const cpyNm = companyName;
const station = { name: "ZB1", readings: [ {temp:47, time: "2016-11-10 09:10"}, {temp:53, time: "2016-11-10 09:20"}, {temp:58, time: "2016-11-10 09:30"}, {temp:53, time: "2016-11-10 09:40"}, {temp:51, time: "2016-11-10 09:50"}, ] }; //정상 범위를 벗어난 측정값 탐색 function readingsOutsideRange(station, min, max){ return station.readings .filter(r => r.temp < min || r.temp > max); } //호출 let alerts = readingsOutsideRange(station, operationPlan.temperatureFloor, operationPlan.temperatureCeiling);
//묶을 클래스 class NumberRange{ constructor(min,max){ this._data = {min:min, max:max}; } get min(){return this._data.min}; get max(){return this._data.max}; }
//새로운 데이터 구조 매개변수 추가 function readingsOutsideRange(station, min, max, range){ return station.readings .filter(r => r.temp < min || r.temp > max); } let alerts = readingsOutsideRange(station, operationPlan.temperatureFloor, operationPlan.temperatureCeiling ,null);//일단 null
//점진적으로 하나씩 줄여가며 테스트 한다. function readingsOutsideRange(station, min, /*max,*/ range){ return station.readings .filter(r => r.temp < min || r.temp > range.max); } const range = new NumberRange(operationPlan.temperatureFloor, operationPlan.temperatureCeiling); let alerts = readingsOutsideRange(station, operationPlan.temperatureFloor, // operationPlan.temperatureCeiling, range);
// 완료 const station = { name: "ZB1", readings: [ {temp:47, time: "2016-11-10 09:10"}, {temp:53, time: "2016-11-10 09:20"}, {temp:58, time: "2016-11-10 09:30"}, {temp:53, time: "2016-11-10 09:40"}, {temp:51, time: "2016-11-10 09:50"}, ] }; function readingsOutsideRange(station, range){ return station.readings .filter(r => r.temp < range.min || r.temp > range.max); } const range = new NumberRange(operationPlan.temperatureFloor, operationPlan.temperatureCeiling); let alerts = readingsOutsideRange(station, range); class NumberRange{ constructor(min,max){ this._data = {min:min, max:max}; } get min(){return this._data.min}; get max(){return this._data.max}; }
//연관된 데이터를 묶음으로서 새로운 설계의 기회를 얻는다. class NumberRange{ constructor(min,max){ this._data = {min:min, max:max}; } get min(){return this._data.min;} get max(){return this._data.max;} contains(arg){return arg>=this.min&&arg<=this.max;} }
let spaceship = {}; let defaultOwner = {firstName:"마틴",lastName:"파울러"}; //참조하는 코드 spaceship.owner = defaultOwner; //갱신하는 코드(불변이라면 갱신 걱정이 없다) defaultOwner = {firstName:"레베카",lastName:"파슨스"};
let spaceship = {}; let defaultOwner = {firstName:"마틴",lastName:"파울러"}; spaceship.owner = defaultOwner; defaultOwner = {firstName:"레베카",lastName:"파슨스"}; //게터/세터 생성 function getDefaultOwner(){return defaultOwner;} function setDefaultOwner(arg){return defaultOwner = arg;}
let spaceship = {}; let defaultOwner = {firstName:"마틴",lastName:"파울러"}; //게터 호출, 대입문은 세터 호출 spaceship.owner = getDefaultOwner(); setDefaultOwner({firstName:"레베카",lastName:"파슨스"}); function getDefaultOwner(){return defaultOwner;} function setDefaultOwner(arg){return defaultOwner = arg;}
let spaceship = {}; //접근 제한자가 없는 언어에서는 이런 식으로 표현하는 것도 도움된다. let __privateOnly_defaultOwner = {firstName:"마틴",lastName:"파울러"}; spaceship.owner = getDefaultOwner(); setDefaultOwner({firstName:"레베카",lastName:"파슨스"}); //저자는 자바스크립트에서는 게터에 get을 빼는 것을 선호함 function defaultOwner(){return __privateOnly_defaultOwner;} function setDefaultOwner(arg){return __privateOnly_defaultOwner = arg;}
자바스크립트에선게터와세터이름을똑같이짓고인수존재여부로구분하는방식을많이쓰기때문에 get을뺸것
값캡슐화하기
//test_refac.mjs import {defaultOwner} from './test_refac.mjs'; import { strict as assert } from 'node:assert'; const owner1 = defaultOwner(); assert.equal("파울러",owner1.lastName,"처음 값 확인"); const owner2 = defaultOwner(); owner2.lastName ="파슨스"; assert.equal("파슨스",owner2.lastName,"owner2 변경 후");
import {defaultOwner} from './test_refac.mjs'; import { strict as assert } from 'node:assert'; const owner1 = defaultOwner(); assert.equal("파울러",owner1.lastName,"처음 값 확인"); const owner2 = defaultOwner(); owner2.lastName ="파슨스"; console.log(owner1); assert.equal("파슨스",owner1.lastName,"owner2 변경 후"); console.log(owner1); ////// 객체 값이 변경된 것을 볼 수 있다. Debugger attached. { firstName: '마틴', lastName: '파슨스' } { firstName: '마틴', lastName: '파슨스' } Waiting for the debugger to disconnect…
let spaceship = {}; let defaultOwnerData = {firstName:"마틴",lastName:"파울러"}; spaceship.owner = defaultOwner(); //방법1 게터에서객체복사본을리턴한다. export function defaultOwner(){return Object.assign({},defaultOwnerData);} export function setDefaultOwner(arg){defaultOwnerData = arg;} 결과
클라이언트에서오히려원본을원하는경우를주의해야한다.
let defaultOwnerData = {firstName:"마틴",lastName:"파울러"}; //방법 2 레코드 캡슐화하기 export function defaultOwner(){return new Person(defaultOwnerData);} export function setDefaultOwner(arg){defaultOwnerData = arg;} class Person{ constructor(data){ this._lastName = data.lastName; this._firstName = data.firstName; } get lastName(){return this._lastName;} get firstName(){return this._firstName;} }
class Book{ addReservation(customer,isPriority) { this._reservations.push(customer); } }
예시: 매개변수를속성으로바꾸기
고객이뉴잉글랜드살고있는지파악하는함수
/* 현재 문제는 매개변수를 객체로 받고 있다. 재사용성이 제한된다.*/ function inNewEngland(aCustomer){ return ["MA","CT","ME","VT","NH","RI"].includes(aCustomer.address.state); } //호출부 const newEnglanders = someCustomers.filter(c=>inNewEngland(c));
function inNewEngland(aCustomer){ const stateCode = aCustomer.address.state; return ["MA","CT","ME","VT","NH","RI"].includes(stateCode); }
function inNewEngland(aCustomer){ const stateCode = aCustomer.address.state; return newFunction(stateCode); } //임시 함수 추출 function newFunction(stateCode) { return ["MA", "CT", "ME", "VT", "NH", "RI"].includes(stateCode); }
function inNewEngland(aCustomer){ //변수 인라인하기 return newFunction(aCustomer.address.state); } function newFunction(stateCode) { return ["MA", "CT", "ME", "VT", "NH", "RI"].includes(stateCode); }
//기본형 function reportLines(aCustomer){ const lines = []; gatherCustomerData(lines, aCustomer); return lines; } function gatherCustomerData(out, aCustomer){ out.push(["name",aCustomer.name]); out.push(["location",aCustomer.location]); }
//매개변수가 다른 경우 리팩터링 function reportLines(aCustomer){ const lines = []; out.push(["name",aCustomer.name]); out.push(["location",aCustomer.location]); return lines; }
function printOwing(invoice){ let outstanding = 0; console.log("******************"); console.log("**** 고객 채무 ****") console.log("******************"); //미해결 채무 for(const o of invoice.orders){ outstanding += o.amount; } //마감일 const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()+30); console.log(`고객명 : ${invoice.customer}`); console.log(`채무액 : ${outstanding}`); console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`); }
//유효범위를 벗어나는 변수가 없을 때 function printOwing(invoice){ let outstanding = 0; printBanner(); //미해결 채무 for(const o of invoice.orders){ outstanding += o.amount; } //마감일 const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()+30); printDetails(); function printDetails() { console.log(`고객명 : ${invoice.customer}`); console.log(`채무액 : ${outstanding}`); console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`); } function printBanner() { console.log("******************"); console.log("**** 고객 채무 ****"); console.log("******************"); } }
리팩터링란에존재
예시: 지역변수를사용할때
지역변수를사용하지만다른값을다시대입하지않을때
//지역 변수를 사용할 때 function printOwing(invoice){ let outstanding = 0; printBanner(); //미해결 채무 for(const o of invoice.orders){ outstanding += o.amount; } //마감일 const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate()+30); //세부 사항을 출력한다 console.log(`고객명 : ${invoice.customer}`); console.log(`채무액 : ${outstanding}`); console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`); function printBanner() { console.log("******************"); console.log("**** 고객 채무 ****"); console.log("******************"); } }
//중첩 함수가 지원되지 않는 언어는 이렇게 넣어줘야 할 것 printDetails(invoice, outstanding); function printDetails(invoice, outstanding) { console.log(`고객명 : ${invoice.customer}`); console.log(`채무액 : ${outstanding}`); console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`); }
recordDueDate(invoice); //중첩 함수가 지원되지 않는 언어는 이렇게 넣어줘야 할 것 printDetails(invoice, outstanding); function recordDueDate(invoice) { const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30); }
예시: 지역변수의값을변경할때
이럴경우매개변수가들어가는지역변수에대한임시변수를새로하나만들어그변수를사용한다.
let outstanding = 0; printBanner(); //미해결 채무 for(const o of invoice.orders){ outstanding += o.amount; }
printBanner(); //문장 슬라이드로 사용되는 곳 근처로 옮김 let outstanding = 0; for(const o of invoice.orders){ outstanding += o.amount; }
printBanner(); let outstanding = 0; for(const o of invoice.orders){ outstanding += o.amount; } //추출할 부분을 새로운 함수로 복사 function calculateOutstanding(invoice){ let outstanding = 0; for(const o of invoice.orders){ outstanding += o.amount; } return outstanding; }
printBanner(); //추출한 함수가 반환한 값을 원래 변수에 저장한다. let outstanding = calculateOutstanding(invoice); function calculateOutstanding(invoice){ let outstanding = 0; for(const o of invoice.orders){ outstanding += o.amount; } return outstanding; }
//마지막으로 반환 값의 이름을 코딩 스타일에 맞게 변경 const outstanding = calculateOutstanding(invoice); function calculateOutstanding(invoice){ let result = 0; for(const o of invoice.orders){ result += o.amount; } return result; }
function printOwing(invoice){ printBanner(); const outstanding = calculateOutstanding(invoice); recordDueDate(invoice); printDetails(invoice, outstanding); function calculateOutstanding(invoice){ let result = 0; for(const o of invoice.orders){ result += o.amount; } return result; } function recordDueDate(invoice) { const today = Clock.today; invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30); } function printDetails(invoice, outstanding) { console.log(`고객명 : ${invoice.customer}`); console.log(`채무액 : ${outstanding}`); console.log(`마감일 : ${invoice.dueDate.toLocaleDateString()}`); } function printBanner() { console.log("******************"); console.log("**** 고객 채무 ****"); console.log("******************"); } }