提炼函数:如下所示:
1.反向重构:内联函数。
2.动机:如果你需要花时间浏览一段代码才能弄清它到底在干什么,那么就应该将其提炼到一个函数中,并根据它所做的事为其命名。以后再读到这段代码时,你一眼就能看到函数的用途,大多数时候根本不需要关心函数如何达成其用途(这是函数体内干的事)。
3.做法:如下所示:
1>.创造一个新函数,根据这个函数的意图来对它命名(以它"做什么"来命名,而不是以它"怎么做"命名)。
2>.将待提炼的代码从源函数复制到新建的目标函数中。
3>.仔细检查提炼出的代码,看看其中是否引用了作用域限于源函数,在提炼出的新函数中访问不到的变量。若是,以参数的形式将它们传递给新函数。
4>.所有变量都处理完之后,编译。
5>.在源函数中,将被提炼代码段替换为对目标函数的调用。
6>.利用测试框架进行测试。
7>.查看其它代码是否有与被提炼的代码段相同或相似之处。如果有,考虑使用该提炼出的新函数进行替换。
4.范例:如下所示:
1>.源代码如下所示:
function printOwing(invoice) {
let outstanding = 0;
console.log("*********************");
console.log("*** Customer Owes ***");
console.log("*********************");
// calculate outstanding
for (const o of invoice.orders) {
outstanding += o.amount;
}
// record due date
const today = Clock.today;
invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.GetDate() + 30);
// print details
console.log('name: ${invoice.customer}');
console.log('amount: ${outstanding}');
console.log('due: ${invoice.dueDate.toLocaleDateString()}');
}
2>.无局部变量情况下进行重构的代码如下所示:
function printOwing(invoice) {
let outstanding = 0;
printBanner();
// calculate outstanding
for (const o of invoice.orders) {
outstanding += o.amount;
}
// record due date
const today = Clock.today;
invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.GetDate() + 30);
printDetails();
function printDetails() {
console.log('name: ${invoice.customer}');
console.log('amount: ${outstanding}');
console.log('due: ${invoice.dueDate.toLocaleDateString()}');
}
}
function printBanner() {
console.log("*********************");
console.log("*** Customer Owes ***");
console.log("*********************");
}
3>.有局部变量情况下进行重构的代码如下所示:
function printOwing(invoice) {
let outstanding = 0;
printBanner();
// calculate outstanding
for (const o of invoice.orders) {
outstanding += o.amount;
}
recordDueDate(invoice);
printDetails(invoice, outstanding);
}
function printBanner() {
console.log("*********************");
console.log("*** Customer Owes ***");
console.log("*********************");
}
function recordDueDate(invoice) {
const today = Clock.today;
invoice.dueDate = new Date(today.getFullYear(), today.getMonth(), today.GetDate() + 30);
}
function printDetails(invoice, outstanding) {
console.log('name: ${invoice.customer}');
console.log('amount: ${outstanding}');
console.log('due: ${invoice.dueDate.toLocaleDateString()}');
}
4>.对局部变量再赋值情况下进行重构的代码如下所示:
function printOwing(invoice) {
printBanner();
const outstanding = calculateOutstanding(invoice);
recordDueDate(invoice);
printDetails(invoice, outstanding);
}
function printBanner() {
console.log("*********************");
console.log("*** Customer Owes ***");
console.log("*********************");
}
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('name: ${invoice.customer}');
console.log('amount: ${outstanding}');
console.log('due: ${invoice.dueDate.toLocaleDateString()}');
}
内联函数:如下所示:
1.反向重构:提炼函数。
2.动机:如下所示:
1>.当手上有一群组织不甚合理的函数时,可以将它们都内联到一个大型函数中,再以喜欢的方式重新提炼出小函数。
2>.当函数的内容和函数的名称变的同样清晰时,就应该去掉这个函数,直接使用其中的代码。
3.做法:如下所示:
1>.检查函数,确定它不具多态性。
2>.找出这个函数的所有调用点。
3>.将这个函数的所有调用点都替换为函数本体。
4>.每次替换之后,执行测试。
5>.删除该函数的定义。
4.范例:如下所示:
1>.源代码如下所示:
function reportLines(aCustomer) {
conse lines = [];
gatherCustomerData(lines, aCustomer);
return lines;
}
function gatherCustomerData(out, aCustomer) {
out.push(["name", aCustomer.name]);
out.push(["location", aCustomer.location]);
}
2>.重构代码如下所示:
function reportLines(aCustomer) {
conse lines = [];
lines.push(["name", aCustomer.name]);
lines.push(["location", aCustomer.location]);
return lines;
}