文档章节

《重构-改善既有代码设计》读书笔记-代码篇

hebaodan
 hebaodan
发布于 2017/08/19 16:01
字数 1293
阅读 96
收藏 0

在《重构》一书中,列举了一些代码的坏味道,同时以举例讲解了重构代码的一些手法,本文是读书后的关于如何写好代码的笔记,主要包括可读性、代码职责、面向对象思维方面。

可读性

下面是一些提升代码可读性的手段、方法。

Extract Method

当一个方法比较复杂、行数较多时,读起来令人费解,这时应该抽取出一个个小段代码的方法,且合理的命名方法,主方法中调用这些方法完成它所做的事情。 当然也不只是方法复杂时需要抽取方法。

优势: 1、通过方法命名,让主方法调用这些方法就能清晰表达主方法的流程,不需要通过注释来解释代码作用 2、方法小了,代码简洁清晰,易于复用

引入解释性变量

代码逻辑繁杂时,或一些复杂运算,可以引入变量,并通过对变量的命名来提升可读性。 如:

	methodB(ClassX.methodC(methodA(a,  b)))
可以改为:
	int someValue = ClassX.methodC(methodA(a,  b));
	methodB(someValue);

不要对方法参数重新赋值

void method(Object A){
	A = new Object();
}

引入参数对象

当方法参列表较长时,提取对象进行包装。一般建议参数个数≤3。

Rename Method/Class

根据代码的功能职责合理命名,便于理解

用对象取代直接使用数组

用常量取代特殊意义的数字

其目的引入解释性变量类似

分解复杂条件表达式

将复杂的表达式拆分成多个简短的表达式,每一个明确其意义。 如:

if(a.status != null && a.status = true && date > XXX && date < YYY){
	......
}
取代为:
if(validStatus(a.status) && valiadDate(date) ){
	......
}

可以更清楚的表达出条件判断的含义

以特殊检查取代嵌套的if else

if与else本身表达的是平级的关系,如果是某些特殊罕见条件特殊处理,采用if return的形式予以重视。 这样能够清晰的体现代码的主流程,不被一些特殊的处理掩盖,读起来更顺畅。 如:

boolean flag;
if(conditionX){
	flag = false;
} else{
	if(conditionY){
		flag = false;
	} else{
		do something……
		flag = calculate();
	}
}
return flag;

改为:

if(conditionX) return false;
if(conditionY) return false;

do something……
flag = calculate();
return flag;

以异常取代错误码

服务内部不要采用错误码来表示错误,如return -1表示失败,而应该抛出异常表达 后端与前端服务间的交互可采用errorCode的方式。 关于异常可参考本人另一篇文章: https://my.oschina.net/hebaodan/blog/1507146

代码职责

我们经常说面向对象的单一职责原则,大到一个系统、模块的职责边界划分,小到一个类、一个方法的职责。 清晰的划分类、方法的职责,保持其单一、稳定的功能,能避免日后代码越来越臃肿。

下面是关于代码职责的处理方法。

Move Method/Field

某个方法不应该属于这个类或package,移动方法到合适的地方。 某个属于不应该属于该对象,移动之。

Extract Class

类越来越大,如某个Service的public方法越来越多,功能混杂,考虑抽取不同的class维护这些方法或属性。

面向对象的思维

用多态取代条件表达式

代码中出现多个if或switch case语句根据不同的条件,采取不同的行为时,应该采用多态的思想。 如:

switch(var){
	case v1:
		behavior1();
		break;
	case v2:
		behavior2();
		break;
	defalut:
		behavior3();
}
可以提炼一个interfa Behavior,根据不同var创建不同的实现类,最后只需要调用behavior.method即可,也是一种策略模式的体现。

但是,上述说法还没彻底解决switch case的问题,因为要创建不同实现类,一种方法是定义一个map存储映射关系。

Method/Field 上移到超类/下移到子类

采用继承时,需要区分出某些属性,方法到底是共性还是特性,共性就应该上移到超类中。特性即仅某些子类才具有,应该下移到子类。合理的进行抽象。

提炼超类/接口/子类

发现代码中有一些共同或类似的行为属性时,要考虑提炼超类or接口。定义好抽象的关系,使代码保持内聚。 关于抽象类与接口参考:https://www.zhihu.com/question/20149818

组合与继承的选择

一般来说组合优先于继承,组合表达的是has a的关系,继承表达的是is a的关系。 组合的扩展性更强,且java不支持多继承。更多关于组合与继承的讨论自行Google吧。

© 著作权归作者所有

hebaodan
粉丝 9
博文 25
码字总数 30036
作品 0
朝阳
程序员
私信 提问
31 天重构学习笔记4. 降低方法

摘要:由于最近在做重构的项目,所以对重构又重新进行了一遍学习和整理,对31天重构最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的blog,所以是在国外的社区上闲逛的时候链接过...

技术小甜
2017/11/15
0
0
31 天重构学习笔记6. 降低字段

摘要:由于最近在做重构的项目,所以对重构又重新进行了一遍学习和整理,对31天重构最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的blog,所以是在国外的社区上闲逛的时候链接过...

技术小甜
2017/11/16
0
0
31 天重构学习笔记10. 提取方法

摘要:由于最近在做重构的项目,所以对重构又重新进行了一遍学习和整理,对31天重构最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的blog,所以是在国外的社区上闲逛的时候链接过...

技术小甜
2017/11/08
0
0
31 天重构学习笔记2. 移动方法

摘要:由于最近在做重构的项目,所以对重构又重新进行了一遍学习和整理,对31天重构最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的blog,所以是在国外的社区上闲逛的时候链接过...

技术小甜
2017/11/15
0
0
31 天重构学习笔记9. 提取接口

摘要:由于最近在做重构的项目,所以对重构又重新进行了一遍学习和整理,对31天重构最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的blog,所以是在国外的社区上闲逛的时候链接过...

技术小甜
2017/11/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

线程池之ThreadPoolExecutor使用

ThreadPoolExecutor提供了四个构造方法: ThreadPoolExecutor构造方法.png 我们以最后一个构造方法(参数最多的那个),对其参数进行解释: public ThreadPoolExecutor(int corePoolSize, /...

天王盖地虎626
23分钟前
1
0
小程序登陆流程

http://www.bubuko.com/infodetail-2592845.html

为何不可1995
32分钟前
1
0
Consul+Spring boot的服务注册和服务注销

一图胜千言 先看一看要做事情,需要在Consul上面实现注册中心的功能,并以2个Spring boot项目分别作为生产者,消费者。 Consul 假设已经完成文章《Consul的开发者模式之Docker版》中的所有的...

亚林瓜子
38分钟前
4
0
MySQL高可用之基于Galera复制跨地域节点分布的滥用

mysql使用教程 MySQL高可用之基于Galera复制跨地域节点分布的滥用 2018-11-22 02:15 8335 85 让我们再一次讨论MySQL高可用性(HA)和同步复制。 它是地理上分布区域上一些高可用性参考架构解...

rootliu
49分钟前
1
0
js判断pc还是移动端

var pcyidong =/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent); 如果pcyidong的值为false则用户的浏览器为pc端 如果pcyidong的值为true则用户浏览器为移动端 if (pcyidong =...

流年那么伤
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部