热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

编写可保护的代码的重要性及优化方法

本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。
编写可保护的代码

媒介

我们在修正别人代码的时刻,浏览别人代码所花的时候常常比完胜利用的时候还要更多

假如顺序结构不清晰,代码杂沓 。牵一发而动全身。那保护起来就更难保护了

可读性

  1. 可邃晓性:别人可以接办代码并邃晓它
  2. 直观性 : 代码逻辑清晰
  3. 可调试性 :失足时,轻易定位题目所在

怎样进步可读性

  1. 代码格式化
  2. 恰当增添解释
  • 函数与要领
  • 大段代码
  • 解释需有意义

怎样优化代码

  1. 找出代码的坏滋味
  2. 应用重构手段将其处置惩罚掉

代码的坏滋味

在我们的顺序中,可以闻到很多的坏滋味。主要有以下这些点

定名不范例或无意义

定名存在应用缩写、不范例、无意义

例子:var a = xxx,b = xxx

反复代码

雷同(或相似)的代码在项目中涌现了屡次,假如需求发作变动,则须要同时修正多个处所

太长函数

顺序越长越难邃晓,一个函数应当只完成一个功用

太长的类

一个类的职责过量,一个类应当是一个自力的团体。

太长参数列表

太长的参数列表难以邃晓,不轻易应用。当须要修正的时刻,会越发轻易失足

数据泥团

有些数据项老是三五成群的待在一同。比方两个类中雷同的字段、很多函数署名雷同的参数。

这些都应当提炼到一个对象中,将很多参数列收缩,简化函数挪用

相似的函数

团体上完成的功用差不多,然则由于有一点点区分。所以写成了多个函数

重构手段

提炼函数

针对一个比较长的函数,提炼成一个个完成特定功用的函数。

例子

// 提炼前
function test11() {
var day = $('day');
var yearVal = '2016';
var mOnthVal= '10';
var dayVal = '10';
day.val(dayVal);
switch (monthVal) {
case 4:
case 6:
case 9:
case 11:
if (dayVal > 30) {
day.val(30);
}
break;
case 2:
if (
yearVal % 4 == 0 &&
(yearVal % 100 != 0 || yearVal % 400 == 0) &&
mOnthVal== 2
) {
if (dayVal > 29) {
day.val(29);
}
} else {
if (dayVal > 28) {
day.val(28);
}
}
break;
default:
if (dayVal > 31) {
day.val(31);
}
}
}

// 提炼后
function test12() {
var day = $('day');
var yearVal = '2016';
var mOnthVal= '10';
var dayVal = '10';
var maxDay = getMaxDay(yearVal, monthVal);
if (dayVal > maxDay) {
day.val(maxDay);
} else {
day.val(dayVal);
}
}
function getMaxDay(year, month) {
var maxDay = 0;
switch (month) {
case 4:
case 6:
case 9:
case 11:
maxDay = 30;
break;
case 2:
if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
maxDay = 29;
} else {
maxDay = 28;
}
break;
default:
maxDay = 31;
}
return maxDay;
}

例子中,提炼前的代码,须要很费力的看完全部函数,才会邃晓做了什么处置惩罚,提炼后的代码。只须要轻微看一下,就晓得 getMaxDay 是猎取当前月份的最大天数

长处:

  1. 假如每一个函数的粒度都很小,那末函数被复用的时机就更大;
  2. 这会使高层函数读起来就想一系列解释;
  3. 假如函数都是细粒度,那末函数的覆写也会更轻易些

内联函数

有时刻,一个函数的本体与函数名一样简朴易懂,就要用到这类手段。

这类手段用于处置惩罚优化过分的题目

举个例子:

function biggerThanZero(num) {
return num > 0;
}
function test() {
var num = 10;
if (biggerThanZero(num)) {
//do something
}
}
//内联后
function test() {
var num = 10;
if (num > 0) {
//do something
}
}

引入解释性变量

当表达式比较庞杂难以浏览的时刻,就可以经由过程暂时变量来协助你将表达式剖析为轻易治理的情势

有些时刻,应用提炼函数会更好一点

举两个简朴的例子:

// 例子 1
// before
function test2() {
if (
platform.toUpperCase().indexOf('MAC') > -1 &&
browser.toUpperCase().indexOf('IE') > -1 &&
wasInitialized() &&
resize > 0
) {
// do something
}
}
// after
function test2() {
var isMacOs = platform.toUpperCase().indexOf('MAC') > -1;
var isIEBrowser = browser.toUpperCase().indexOf('IE') > -1;
var wasResized = resize > 0;
if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
// do something
}
}
// --------------------------------------------------
// 例子2
// before
function caluPrice(quantity, itemPrice) {
return (
quantity * itemPrice -
Math.max(0, quantity - 500) * itemPrice * 0.05 +
Math.min(quantity * itemPrice * 0.1, 100)
);
}
// after
function caluPrice(quantity, itemPrice) {
var basePrice = quantity * itemPrice;
var discount = Math.max(0, quantity - 500) * itemPrice * 0.05;
var shiping = Math.min(basePrice * 0.1, 100);
return basePrice - discount + shiping;
}

在两个例子中,引入解释性的变量以后,可读性大大增添。函数的企图就比较显著,单看变量定名就已能也许晓得详细的完成

剖析暂时变量

  • 除了 for 轮回里用来网络效果的变量,其他的暂时变量都应当只被赋值一次。
  • 由于被赋值凌驾一次,就意味着他在函数中负担了多个义务。
  • 一个变量负担多个义务。会令代码看起来轻易疑惑

举个例子:

// 剖析暂时变量
// before
function test3() {
var temp = 2 * (width + height);
console.log(temp);
// do something
temp = height * width;
// do something
console.log(temp);
}
// after
function test4() {
var perimeter = 2 * (width + height);
console.log(perimeter);
// do something
var area = height * width;
// do something
console.log(area);
}

在这个例子中,temp 分别被给予了两次,假如代码块较长的状况,会增添风险,由于你不晓得他在那里被改掉了

替代算法

当你重构的时刻,发明完成一样的功用有一个更清晰的体式格局,就应当将原有的算法替代成你的算法。

举个例子:

// 替代算法
// before
function getWeekDay() {
var weekStr = '';
switch (date.format('d')) {
case 0:
weekStr = '日';
break;
case 1:
weekStr = '一';
break;
case 2:
weekStr = '二';
break;
case 3:
weekStr = '三';
break;
case 4:
weekStr = '四';
break;
case 5:
weekStr = '五';
break;
case 6:
weekStr = '六';
break;
}
return weekStr;
}
// after
function getWeekDay() {
var weekDays = ['日', '一', '二', '三', '四', '五', '六'];
return weekDays[date.format('d')];
}

以字面常量庖代魔法数(eg:状况码)

在计算机科学中,魔法数是汗青最悠长的不良现象之一。

魔法数是指顺序中稀里糊涂的数字。具有特别意义,却又不能明白表现出这类意义的数字

举个例子:

// before
function test5(x) {
if (x == 1) {
console.log('完成');
} else if (x == 2) {
console.log('上传中');
} else if (x == 3) {
console.log('上传失利');
} else {
console.log('未知的毛病');
}
}
function test6(x) {
if (x == 3) {
// do something
}
}
// after
var UploadStatus = {
START: 0,
UPLOADING: 1,
SUCCESS: 2,
ERROR: 3,
UNKNOWN: 4
};
function test7(x) {
if (x == UploadStatus.START) {
console.log('未最先');
} else if (x == UploadStatus.UPLOADING) {
console.log('上传中');
} else if (x == UploadStatus.SUCCESS) {
console.log('上传胜利');
} else if (x == UploadStatus.ERROR) {
console.log('上传失利');
} else {
console.log('未知的毛病');
}
}
function test8(x) {
if (x == UploadStatus.ERROR) {
// do something
}
}

关于魔法数,应当用一个罗列对象或一个常量来给予其可见的意义。如许,你在用到的时刻,就可以明白的晓得它代表的是什么意义

而且,当需求变化的时刻,只须要转变一个处所即可

剖析前提表达式

庞杂的前提逻辑是致使庞杂度上升的所在之一。由于必需编写代码来处置惩罚差别的分支,很轻易就写出一个相称长的函数

将每一个分支前提剖析成新函数可以凸起前提逻辑,更清晰表明每一个分支的作用以及缘由

举个例子:

// 剖析前提表达式
// 商品在冬季和夏日单价不一样
// before
var SUMMER_START = '06-01';
var SUMMER_END = '09-01';
function test9() {
var quantity = 2;
var winterRate = 0.5;
var winterServiceCharge = 9;
var summerRate = 0.6;
var charge = 0;
if (date.before(SUMMER_START) || date.after(SUMMER_END)) {
charge = quantity * winterRate + winterServiceCharge;
} else {
charge = quantity * summerRate;
}
return charge;
}
// after
function test9() {
var quantity = 2;
return notSummer(date) ? winterCharge(quantity) : summerCharge(quantity);
}
function notSummer(date) {
return date.before(SUMMER_START) || date.after(SUMMER_END);
}
function summerCharge(quantity) {
var summerRate = 0.6;
return quantity * summerRate;
}
function winterCharge(quantity) {
var winterRate = 0.5;
var winterServiceCharge = 9;
return quantity * winterRate + winterServiceCharge;
}

兼并前提表达式

当发明一系列的前提搜检,搜检前提不一样,然则行动却一致。就可以将它们兼并为一个前提表达式

举个例子:

// 兼并前提表达式
// before
function test10(x) {
var isFireFox = 'xxxx';
var isIE = 'xxxx';
var isChrome = 'xxxx';
if (isFireFox) {
return true;
}
if (isIE) {
return true;
}
if (isChrome) {
return true;
}
return false;
}
// after
function test10(x) {
var isFireFox = 'xxxx';
var isIE = 'xxxx';
var isChrome = 'xxxx';
if (isFireFox || isIE || isChrome) {
return true;
}
return false;
}

兼并后的代码会通知你,实际上只要一个前提搜检,只是有多个并列前提须要搜检罢了

兼并反复的前提片断

前提表达式上有着雷同的一段代码,就应当将它搬离出来

// 兼并反复片断
// before
function test11(isSpecial) {
var total,
price = 1;
if (isSpecial) {
total = price * 0.95;
// 这里处置惩罚一些营业
} else {
total = price * 0.8;
// 这里处置惩罚一些营业
}
}
// after
function test12(isSpecial) {
var total,
price = 1;
if (isSpecial) {
total = price * 0.95;
} else {
total = price * 0.8;
}
// 这里处置惩罚一些营业
}

在差别的前提内里做了一样的事变,应当将其抽离出前提推断。如许代码量少而且逻辑越发清晰

以卫语句庖代嵌套前提表达式

假如某个前提较为稀有,应当零丁搜检该前提,并在该前提为真时立即从函数中返回。如许的搜检就叫卫语句

举个例子:

// 以卫语句庖代嵌套前提表达式
// before
function getPayMent() {
var result = 0;
if (isDead) {
result = deadAmount();
} else {
if (isSepartated) {
result = separtedAmount();
} else {
if (isRetired) {
result = retiredAmount();
} else {
result = normalPayAmount();
}
}
}
return result;
}
// after
function getPayMent() {
if (isDead) {
return deadAmount();
}
if (isSepartated) {
return separtedAmount();
}
if (isRetired) {
return retiredAmount();
}
return normalPayAmount();
}

函数更名(定名)

当函数称号不能表达函数的用处,就应当更名

  1. 变量和函数应应用合乎逻辑的名字。

    eg:猎取产物列表 -> getProductList()

  2. 变量名应为名词,由于变量名形貌的大部分是一个事物。

    eg: 产物 -> product

  3. 函数名应为动词最先,由于函数形貌的是一个行动

    eg:猎取产物列表 -> getProductList()

将查询函数和修正函数离开

假如某个函数只向你供应一个值,没有任何副作用。这个函数就可以恣意的挪用。

如许的函数称为纯函数

假如碰到一个既有返回值,又有副作用的函数。就应当将查询与修正行动分离出来

举个例子:

// before
function test13(people) {
for (var i = 0, len = people.length; i if (people[i].name == 'andy') {
// do something 比方举行DOM 操纵之类的
return 'andy';
}
if (people[i].name == 'ChunYang') {
// do something 比方举行DOM 操纵之类的
return 'ChunYang';
}
}
}
// after
function test14(people) {
var p = find(people);
// do something 比方举行DOM 操纵之类的
// doSomeThing(p);
}
function find(people) {
for (var i = 0, len = people.length; i if (people[i].name == 'andy') {
return 'andy';
}
if (people[i].name == 'ChunYang') {
return 'ChunYang';
}
}
}

令函数照顾参数

假如发明两个函数,做着相似的事情。区分只在于个中几个变量的差别。就可以经由过程参数来处置惩罚。

如许可以去除反复的代码,进步灵活性

症结点: 找出差别的处所和反复的处所。

引荐书本

《重构 改良既有代码的设想 》 基于 java 的

《代码大全》

相干链接

个人博客
代码片断


推荐阅读
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 【MicroServices】【Arduino】装修甲醛检测,ArduinoDart甲醛、PM2.5、温湿度、光照传感器等,数据记录于SD卡,Python数据显示,UI5前台,微服务后台……
    这篇文章介绍了一个基于Arduino的装修甲醛检测项目,使用了ArduinoDart甲醛、PM2.5、温湿度、光照传感器等硬件,并将数据记录于SD卡,使用Python进行数据显示,使用UI5进行前台设计,使用微服务进行后台开发。该项目还在不断更新中,有兴趣的可以关注作者的博客和GitHub。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • 小程序wxs中的时间格式化以及格式化时间和date时间互转
    本文介绍了在小程序wxs中进行时间格式化操作的问题,并提供了解决方法。同时还介绍了格式化时间和date时间的互相转换的方法。 ... [详细]
  • React基础篇一 - JSX语法扩展与使用
    本文介绍了React基础篇一中的JSX语法扩展与使用。JSX是一种JavaScript的语法扩展,用于描述React中的用户界面。文章详细介绍了在JSX中使用表达式的方法,并给出了一个示例代码。最后,提到了JSX在编译后会被转化为普通的JavaScript对象。 ... [详细]
  • 本文介绍了PHP常量的定义和使用方法,包括常量的命名规则、大小写敏感性、全局范围和标量数据的限制。同时还提到了应尽量避免定义resource常量,并给出了使用define()函数定义常量的示例。 ... [详细]
  • Postgresql备份和恢复的方法及命令行操作步骤
    本文介绍了使用Postgresql进行备份和恢复的方法及命令行操作步骤。通过使用pg_dump命令进行备份,pg_restore命令进行恢复,并设置-h localhost选项,可以完成数据的备份和恢复操作。此外,本文还提供了参考链接以获取更多详细信息。 ... [详细]
  • centos安装Mysql的方法及步骤详解
    本文介绍了centos安装Mysql的两种方式:rpm方式和绿色方式安装,详细介绍了安装所需的软件包以及安装过程中的注意事项,包括检查是否安装成功的方法。通过本文,读者可以了解到在centos系统上如何正确安装Mysql。 ... [详细]
author-avatar
backup哗哗-1996
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有