国外建筑设计网站,网站打开是别人的,百度搜索引擎的使用方法,汝阳网站建设概述
在这一章节#xff0c;作者给出了一个戏剧演出团售票的示例#xff1a;剧目有悲剧#xff08;tragedy#xff09;和喜剧#xff08;comedy#xff09;#xff1b;为了卖出更多的票#xff0c;剧团则更具观众的数量来为下次演出打折扣#xff08;大致意思是这次的…概述
在这一章节作者给出了一个戏剧演出团售票的示例剧目有悲剧tragedy和喜剧comedy为了卖出更多的票剧团则更具观众的数量来为下次演出打折扣大致意思是这次的观众越多下次的票价越低
设计
采用JSON存储数据因为代码是用Javascript写的plays.json 存储剧目invoices.json存储账单
plays.json
{hamlet: {name: Hamlet, type: tragedy},as-like: {name: As You Like It, type: comedy},othello: {name: Othello, type: tragedy}
}invoices.json
[{customer: BigCo,performances: [{playID: hamlet,audience: 55 },{playID: as-like,audience: 35},{playID: othello,audience: 40}]
}]下面这个函数用于打印账单详情
function statement(invoice, plays) {let totalAmount 0;let volumeCredits 0;let result Statement for ${invoice.customer}\n;const format new Intl.NumberFormat(en-US, {style: currency,currency: USD,minimumFractionDigits: 2}).format;for (let perf of invoice.performances) {const play plays[perf.playID];let thisAmount 0;switch (play.type) {case tragedy:thisAmount 40000;if (perf.audience 30) {thisAmount 1000 * (perf.audience - 30);}break;case comedy:thisAmount 30000;if (perf.audience 20) {thisAmount 10000 500 * (perf.audience - 20);}thisAmount 300 * perf.audience;break;default:throw new Error(unknown type: ${play.type});}// add volume creditsvolumeCredits Math.max(perf.audience - 30, 0);// add extra credit for every ten comedy attendeesif (comedy play.type) volumeCredits Math.floor(perf.audience / 5);// print line for this orderresult ${play.name}: ${format(thisAmount/100)} (${perf.audience} seats)\n;totalAmount thisAmount;}result Amount owed is ${format(totalAmount/100)}\n;result You earned ${volumeCredits} credits\n;return result;
}函数statement实现的打印账单的功能能正常工作但是其结构“不甚清晰”。对于这个几十行的代码我们要读懂、理解并不困难如果业务比较复杂、函数很长上百行时笔者在维护既有项目时见过2000多行的函数阅读代码就像是在考古再去阅读或者让其他人阅读要弄清逻辑确实需要花费一番功夫。
如果没有新的需求导入statement保持现状也可忍受
新的需求导入
要求输出部分以HTML的格式扩充新的剧目类型如历史剧、田园剧等……
需求会源源不断的导入如果每次导入一个的需求都在statement函数中修改随着时间的推移statement函数将变得臃肿不堪、难以阅读和理解这也是我们工作中经常做的目的是懒省事儿需求来了在既有的函数中改改能实现功能就完事。
分解函数statement
提取amountFor函数for循环中的代码注意提取参数啊Performance、play提取playFor函数play参数不是for循环的变量而是计算出来的修改amountFor函数减去play参数volumeCredits累加变量提取volumeCreditsFor函数提取format函数格式化数据……
具体过程参考《重构改善既有代码设计第二版》第一章
function statement(invoice, plays) {let result Statement for ${invoice.customer}\n;for (let perf of invoice.performances) {result ${playFor(perf).name}: ${usd(amountFor(perf))} (${perf.audience} s
eats)\n;}result Amount owed is ${usd(totalAmount())}\n;result You earned ${totalVolumeCredits()} credits\n;return result;function totalAmount() {let result 0;for (let perf of invoice.performances) {result amountFor(perf);}return result;}function totalVolumeCredits() {let result 0;for (let perf of invoice.performances) {result volumeCreditsFor(perf);}return result;}function usd(aNumber) {return new Intl.NumberFormat(en-US, {style: currency,currency: USD,minimumFractionDigits: 2}).format(aNumber / 100);}function volumeCreditsFor(aPerformance) {let result 0;result Math.max(aPerformance.audience - 30, 0);if (comedy playFor(aPerformance).type) result Math.floor(aPerformance.audience / 5);return result;}function playFor(aPerformance) {return plays[aPerformance.playID];}function amountFor(aPerformance) {let result 0;switch (playFor(aPerformance).type) {case tragedy:result 40000;if (aPerformance.audience 30) {result 1000 * (aPerformance.audience - 30);}break;case comedy:result 30000;if (aPerformance.audience 20) {result 10000 500 * (aPerformance.audience - 20);}result 300 * aPerformance.audience;break;default:throw new Error(unknown type: ${playFor(aPerformance).type});}return result;}
}拆分计算阶段与格式化阶段分离到两个文件……
总结
一般来说重构早期的主要动力是尝试理解代码如何工作。通常我们需要先通读代码找到一些感觉然后再通过重构将这些感觉从脑海里搬回到代码中。清晰的代码更容易理解使你能够发现更深层次的设计问题从而形成积极正向的反馈环。
所谓重构refactoring是这样一个过程在不改变代码外在行为的前提下对代码做出修改以改进程序的内部结构。重构是一种经千锤百炼形成的有条不紊的程序整理方法可以最大限度地减小整理过程中引入错误的概率。本质上说重构就是在代码写好之后改进它的设计。
有了重构以后工作的平衡点开始发生变化。设计不是在一开始完成的而是在整个开发过程中逐渐浮现出来。在系统构筑过程中我们需要学会如何不断改进设计。这个“构筑-设计”的反复互动可以让一个程序在开发过程中持续保有良好的设计。