《重构》读书笔记【第1章 重构,第一个示例,第2章 重构原则】

server/2024/9/22 17:34:21/

文章目录

第1章 重构,第一个示例

我这里使用的IDE是IntelliJ IDEA

1.1 重构

  • plays.js
javascript">export const plays = {"hamlet": {"name": "Hamlet", "type": "tragedy"},"as-like": {"name": "As You Like It", "type": "comedy"},"othello": {"name": "Othello", "type": "tragedy"}
};
  • invoice.js
javascript">export const invoice = {"customer": "BigCo","performances": [{"playID": "hamlet","audience": 55},{"playID": "as-like","audience": 35},{"playID": "othello","audience": 40}]
}
  • statement.js
javascript">import {plays} from "./plays.js";
import {invoice} from "./invoice.js";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;
}let res = statement(invoice, plays);
console.log(res);
  • package.json
{"name": "untitled","version": "1.0.0","type": "module","dependencies": {}
}

运行结果

Statement for BigCoHamlet: $650.00 (55 seats)As You Like It: $580.00 (35 seats)Othello: $500.00 (40 seats)
Amount owed is $1,730.00
You earned 47 credits

1.2 重构

  • plays.js
javascript">export const plays = {"hamlet": {"name": "Hamlet", "type": "tragedy"},"as-like": {"name": "As You Like It", "type": "comedy"},"othello": {"name": "Othello", "type": "tragedy"}
};
  • invoice.js
javascript">export const invoice = {"customer": "BigCo","performances": [{"playID": "hamlet","audience": 55},{"playID": "as-like","audience": 35},{"playID": "othello","audience": 40}]
}
  • package.json
{"name": "untitled","version": "1.0.0","type": "module","dependencies": {}
}
  • createStatementData.js
javascript">class PerformanceCalculator {constructor(aPerformance, aPlay) {this.performance = aPerformance;this.play = aPlay;}get volumeCredits() {return Math.max(this.performance.audience - 30, 0);}get amount() {throw new Error("subclass responsibility");}
}class TragedyCalculator extends PerformanceCalculator {get amount() {let result = 40000;if (this.performance.audience > 30) {result += 1000 * (this.performance.audience - 30);}return result;}
}class ComedyCalculator extends PerformanceCalculator {get amount() {let result = 30000;if (this.performance.audience > 20) {result += 10000 + 500 * (this.performance.audience - 20);}result += 300 * this.performance.audience;return result;}get volumeCredits() {return super.volumeCredits + Math.floor(this.performance.audience / 5);}
}function createPerformanceCalculator(aPerformance, aPlay) {switch (aPlay.type) {case "tragedy":return new TragedyCalculator(aPerformance, aPlay);case "comedy":return new ComedyCalculator(aPerformance, aPlay);default:throw new Error(`unknown type: ${aPlay.type}`);}
}export function createStatementData(invoice, plays) {const statementData = {};statementData.customer = invoice.customer;statementData.performances = invoice.performances.map(enrichPerformances);statementData.totalAmount = totalAmount(statementData);statementData.totalVolumeCredits = totalVolumeCredits(statementData);return statementData;function enrichPerformances(aPerformance) {const calculator = createPerformanceCalculator(aPerformance, playFor(aPerformance));const result = Object.assign({}, aPerformance);result.play = calculator.play;result.amount = calculator.amount;result.volumeCredits = calculator.volumeCredits;return result;}function playFor(aPerformance) {return plays[aPerformance.playID];}function totalAmount(data) {return data.performances.reduce((total, p) => total + p.amount, 0);}function totalVolumeCredits(data) {return data.performances.reduce((total, p) => total + p.volumeCredits, 0);}
}
  • statement.js
javascript">import {plays} from "./plays.js";
import {invoice} from "./invoice.js";
import {createStatementData} from "./createStatementData.js";function statement(invoice, plays) {return renderPlainText(createStatementData(invoice, plays));
}function renderPlainText(data) {let result = `Statement for ${data.customer}\n`;for (let perf of data.performances) {result += ` ${perf.play.name}: ${usd(perf.amount)} (${perf.audience} seats)\n`;}result += `Amount owed is ${usd(data.totalAmount)}\n`;result += `You earned ${(data.totalVolumeCredits)} credits\n`;return result;
}function htmlStatement (invoice, plays) {return renderHtml(createStatementData(invoice, plays));
}
function renderHtml (data) {let result = `<h1>Statement for ${data.customer}</h1>\n`;result += "<table>\n";result += "<tr><th>play</th><th>seats</th><th>cost</th></tr>";for (let perf of data.performances) {result += ` <tr><td>${perf.play.name}</td><td>${perf.audience}</td>`;result += `<td>${usd(perf.amount)}</td></tr>\n`;}result += "</table>\n";result += `<p>Amount owed is <em>${usd(data.totalAmount)}</em></p>\n`;result += `<p>You earned <em>${data.totalVolumeCredits}</em> credits</p>\n`;return result;
}function usd(aNumber) {return new Intl.NumberFormat("en-US",{style: "currency", currency: "USD",minimumFractionDigits: 2}).format(aNumber / 100);
}let res = statement(invoice, plays);
console.log(res);
let assert_res = "Statement for BigCo\n" +" Hamlet: $650.00 (55 seats)\n" +" As You Like It: $580.00 (35 seats)\n" +" Othello: $500.00 (40 seats)\n" +"Amount owed is $1,730.00\n" +"You earned 47 credits\n"console.log(res === assert_res)

第2章 重构原则

2.1 何谓重构

重构(名词):在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。

重构(动词):使用重构手法,在不改变软件可观察行为的前提下,调整其结构。

重构的过程中,代码必须保持可用。如果重构导致代码不可用,那么它不可以称之为重构

重构与性能优化的对比

重构性能优化
都修改代码,都不改变系统功能都修改代码,都不改变系统功能
为了可读性,为了可扩展性为了提升系统性能

2.2 两顶帽子

  • 添加新功能:不应该修改已有代码,只关注新功能。增加新测试,通过测试衡量工作进度
  • 重构:只改变程序内部结构,不应该添加测试(存在遗漏),不修改测试(除非接口发生变化)
  • 软件开发在这两者之间切换

2.3 为何重构

  • 改进软件设计:程序的设计在没有重构的情况下逐渐腐败变质,功能的增加或者修改可能使代码越来越难以理解。
  • 软件更容易理解:提高代码可读性。
  • 帮助找出bug:这个是建立在代码容易理解之上的。
  • 提高编程速度:良好设计降低开发和理解成本。

请添加图片描述

2.4 何时重构

  • 事不过三,三则重构:重复性问题若出现三次,就应该考虑重构

见机行事重构

  • 预备性重构:最佳时机是在添加新功能之前进行,磨刀不误砍柴工。
  • 阅读时重构:遇到难以理解的代码时,考虑是否可以通过重构使其更清晰。
  • 人的思考资源宝贵重构就是把理解转移到代码中,沉淀知识。
  • 捡垃圾式重构:“童子军军规”——至少让营地比你来时更干净。

有计划的重构

  • 日常编程中的重构重构应是为了自己,而非单独排期。

  • 长期重构:大型重构应由整个团队共同参与,逐步推进。

  • CodeReview时的重构:考虑他人的理解,提高代码和设计的可读性。

  • 添加功能时重构:一方面可能是需要理解需要修改的代码,另一方面是使增加新特性更加容易。

  • 修补错误时重构:出现bug的时候,难以找出问题所在的时候,很有可能是代码不清晰导致查找bug的困难。

何时不应重构

  • 不需人理解的抽象代码:不需人常常修改,可放任自流。
  • 重写成本低于重构:若从头开始更经济,无需重构

2.5 重构和开发过程

重构中不断集成,基于主干开发,保证自测试用例的完整性,CI(持续集成)、自动化测试和重构是不可分割的三位一体。


http://www.ppmy.cn/server/53499.html

相关文章

SQL面试真题解答 数据统计分析,求“同比、环比”等(SQL窗口函数使用)

SQL面试真题解答 数据统计分析&#xff0c;求“同比、环比”等&#xff08;SQL窗口函数使用&#xff09; 环比、环比增长率、同比、同比增长率&#xff0c;根据百度百科上的 说明&#xff1a; 环比增长率 环比增长率&#xff0c;一般是指和上期相比较的增长率。 环比增长率&a…

Hadoop 面试题(九)

1. 简述下面关于Hadoop系统中使用CombineFileInputFormat解决小文件问题的描述错误的是&#xff08;&#xff09; &#xff1f; A&#xff1a;CombineFileInputFormat是使用Hadoop API(抽象类CombineFileInputFormat)来解决小文件的问题 B&#xff1a;抽象类CombineFileInputF…

新型裂变营销,茶叶店茶馆会员卡模式,社交电商新玩法分享

大多数茶叶店只是简单地售卖茶叶&#xff0c;偶尔附赠一些茶点作为促销手段。然而&#xff0c;这家茶叶店的老板却采用了与众不同的商业模式&#xff0c;成功吸引了周围8家同行80%的客户。 接下来&#xff0c;让我们揭开这家茶叶店成功的秘密。 首先&#xff0c;他们推出了一个…

计算机网络微课堂(湖科大教书匠)TCP部分

计算机网络微课堂&#xff08;湖科大教书匠&#xff09;TCP部分 【计算机网络微课堂&#xff08;有字幕无背景音乐版&#xff09;】 TCP的流量控制 一般来说&#xff0c;我们希望数据传输得更快一些。但如果发送方把数据发送得过快&#xff0c;接收方就可能来不及接收&#…

存储请求地址但是使用时请求的是端口

baseURL默认全局加载一次&#xff0c;后续直接读取缓存 解决方案&#xff1a;

【课程总结】Day10:卷积网络的基本组件

前言 由于接下来的课程内容将围绕计算机视觉展开&#xff0c;其中接触最多的内容是卷积、卷积神经网络等…因此&#xff0c;本篇内容将从卷积入手&#xff0c;梳理理解&#xff1a;卷积的意义、卷积在图像处理中的作用以及卷积神经网络的概念&#xff0c;最后利用pytorch搭建一…

whisper 实现语音转文字

准备需要转码的音频 https://support.huaweicloud.com/sdkreference-sis/sis_05_0039.html 编码转吗的代码 import whisperif __name__ "__main__":file_path "16k16bit.wav"model whisper.load_model("small")result model.transcribe(f…

Docker 镜像

简单介绍 容器镜像是一个只读包&#xff0c;它包含运行应用程序所需的一切。它包括应用程序代码、应用程序依赖项、一组最基本的操作系统结构和元数据。一个镜像可用于启动一个或多个容器。 如果你熟悉 VMware&#xff0c;就会认为映像与 VM 模板类似。虚拟机模板就像一个停止…