- 浏览: 1036829 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
繁星水:
Useful!!
Object-C之(Null)与(Bool) -
pacer123:
请问注解@ApiModelProperty 在哪个jar包下面 ...
Micro Service工具集之Swagger:可测试的样式化API文档 -
sucheng2016:
这东东真的好用么/
对象转换利器之Dozer -
zzq0324:
http://git.oschina.net/zzq0324/ ...
基于Spring-WS的Restful API的集成测试 -
lrz0534:
你好,我在maven上面下载了swagger-springmv ...
Micro Service工具集之Swagger:可测试的样式化API文档
所谓重构(Refactoring)就是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。
定义很明确,清楚,但是怎么证明重构真的改善了代码的质量,性能?怎么证明重构提高了软件的扩展性合并可维护性呢? 换句话说,怎么证明我们花在重构上的时间真的产生了价值?
在软件代码的开发中,坏味道是公认的不好的代码,而设计模式,Clean Code是公认的好的代码,因此,如果能够把有坏味道的代码重构为使用模式的代码,或者符合Clean Code标准的代码, 那么就可以认为重构改善了代码的质量,提高了代码的可扩展性和可维护性,这个从不好的代码到好的代码就是重构产生的价值。
从上面的论述中,可以看出,任何重构一定是基于代码坏味道的,因此,重构的基础是对代码坏味道的识别能力,任何不是针对代码坏味道的重构都是耍流氓。
在做重构时,通常会涉及到3种类型的重构:
一是某个类内部的修改,包括重命名,抽取方法等等,这类重构很简单,有编程经验的程序员们基本上都会;
二是把多个类的相同代码,往上提,从而整合出一个类层次结构,以方便代码复用,提高扩展性等等。
三是把多个类中功能相似的代码提取出来,归总到一个类中。
接下来就通过一个例子来看一下这整个的重构过程:有一个停车场ParkingLot,,这是第一阶段的需求,对于ParkingLot的实现如下:
第三阶段需求,有另外一个泊车小弟VacancyParker, 它也管理一批停车场,但是他放车的顺序是按照停车场空置率,哪个停车场空置率高就放哪个停车场。于是VacancyParker的代码如下:
模式就出来了。
第四阶段需求,有一个ParkerManager,它负责管理几个Parker,为了了解他管理的整个停车场的状态,需要获取其管理的所有停车场的状态报告,按如下格式:
parkerManager:
Parker1:
ParkingLot1:10/21 (注:共有21个车位,˙其中10个有车)
ParkingLot2:8/21
Parker2:
ParkingLot1:10/21
ParkingLot2:8/21
..........
实现这个需求时,第一阶段的代码如下:
Parker中的关于report()方法的代码如下:
ParkingLot中关于report的方法如下:
如果,还有新的需求,我们可以继续通过如上的方法,明确需求-》查找合适的设计模式 -》重构出这个设计模式,保持一个干净的代码环境。
总结:
1、简单设计,以最快的速度实现当前需求
2、TDD保证重构信心
3、模式是重构出来
4、保持对代码异味的高度敏感性
本文中的示例代码地址:https://github.com/xianlinbox/ChessDemo/tree/master/src/main/java/parkinglot
定义很明确,清楚,但是怎么证明重构真的改善了代码的质量,性能?怎么证明重构提高了软件的扩展性合并可维护性呢? 换句话说,怎么证明我们花在重构上的时间真的产生了价值?
在软件代码的开发中,坏味道是公认的不好的代码,而设计模式,Clean Code是公认的好的代码,因此,如果能够把有坏味道的代码重构为使用模式的代码,或者符合Clean Code标准的代码, 那么就可以认为重构改善了代码的质量,提高了代码的可扩展性和可维护性,这个从不好的代码到好的代码就是重构产生的价值。
从上面的论述中,可以看出,任何重构一定是基于代码坏味道的,因此,重构的基础是对代码坏味道的识别能力,任何不是针对代码坏味道的重构都是耍流氓。
在做重构时,通常会涉及到3种类型的重构:
一是某个类内部的修改,包括重命名,抽取方法等等,这类重构很简单,有编程经验的程序员们基本上都会;
二是把多个类的相同代码,往上提,从而整合出一个类层次结构,以方便代码复用,提高扩展性等等。
三是把多个类中功能相似的代码提取出来,归总到一个类中。
接下来就通过一个例子来看一下这整个的重构过程:有一个停车场ParkingLot,,这是第一阶段的需求,对于ParkingLot的实现如下:
public class ParkingLot { private Map<ParkingTicket, Car> carports = new HashMap<ParkingTicket, Car>(); private int capacity; private int spaces; public ParkingLot(int capacity) { this.capacity = capacity; this.spaces = capacity; } public ParkingTicket park(Car car) { if(spaces == 0){ return null; } ParkingTicket ticket = new ParkingTicket(); carports.put(ticket, car); spaces--; return ticket; } public boolean isFull() { return spaces == 0; } public Car unpark(ParkingTicket ticket) { return carports.get(ticket); } }首先,对于park()方法的逻辑有点多,进行第一步重构,在park()方法的整个逻辑应该是获取一个停车位,然后把车停进去。因此可以把park方法按如下修改:
public ParkingTicket park(Car car) { return isFull() ? null : parkCarIntoCarport(car); } public boolean isFull() { return spaces == 0; } private ParkingTicket parkCarIntoCarport(Car car) { ParkingTicket ticket = new ParkingTicket(); carports.put(ticket, car); spaces--; return ticket; },接下来,第二阶段的需求,有一个泊车小弟Parker,管理一批停车场ParkingLot,每次有车来,他都按照顺序一个停车场停满再停下一个停车场。实现这个Parker的代码如下:
public class Parker { private List<ParkingLot> parkingLotList = new ArrayList<ParkingLot>(); public void addParkingLot(ParkingLot parkingLot) { parkingLotList.add(parkingLot); } public ParkingTicket park(Car car) { for (ParkingLot parkingLot : parkingLotList) { if (!parkingLot.isFull()) { return parkingLot.park(car); } } return null; } public Car unpark(ParkingTicket ticket) { for (ParkingLot parkingLot : parkingLotList) { if (parkingLot.unpark(ticket) != null) { return parkingLot.unpark(ticket); } } return null; } }
第三阶段需求,有另外一个泊车小弟VacancyParker, 它也管理一批停车场,但是他放车的顺序是按照停车场空置率,哪个停车场空置率高就放哪个停车场。于是VacancyParker的代码如下:
public class VacancyParker { private List<ParkingLot> parkingLotList = new ArrayList<ParkingLot>(); public void addParkingLot(ParkingLot parkingLot) { parkingLotList.add(parkingLot); } public ParkingTicket park(Car car) { ParkingLot choosedLot = null; double vacancyRate = 0; for (ParkingLot parkingLot : parkingLotList) { if (parkingLot.vacancyRate() > vacancyRate) { vacancyRate = parkingLot.vacancyRate(); choosedLot = parkingLot; } } return choosedLot.park(car); } public Car unpark(ParkingTicket ticket) { for (ParkingLot parkingLot : parkingLotList) { if (parkingLot.unpark(ticket) != null) { return parkingLot.unpark(ticket); } } return null; } },在这个阶段,我们把VacancyParker的park()方法整理一下,如下:
public ParkingTicket park(Car car) { ParkingLot choosedLot = choosePark(); return choosedLot == null ? null : choosedLot.park(car); } private ParkingLot choosePark() { ParkingLot choosedLot = null; double vacancyRate = 0; for (ParkingLot parkingLot : parkingLotList) { if (parkingLot.vacancyRate() > vacancyRate) { vacancyRate = parkingLot.vacancyRate(); choosedLot = parkingLot; } } return choosedLot; }整理之后,就能发现一个很明显的代码异味,就是Parker和VacancyParker的代码重复特别多,除了在选择ParkingLot的逻辑上之外,其他的代码都是一样的,因此我们可以把代码重构为如下的类层次结构:
模式就出来了。
第四阶段需求,有一个ParkerManager,它负责管理几个Parker,为了了解他管理的整个停车场的状态,需要获取其管理的所有停车场的状态报告,按如下格式:
parkerManager:
Parker1:
ParkingLot1:10/21 (注:共有21个车位,˙其中10个有车)
ParkingLot2:8/21
Parker2:
ParkingLot1:10/21
ParkingLot2:8/21
..........
实现这个需求时,第一阶段的代码如下:
public class ParkerManager { private List<Parker> parkers = new ArrayList<Parker>(); public void addParker(Parker parker) { parkers.add(parker); } public String report() { StringBuilder stringBuilder = new StringBuilder().append("manager:\n"); for (Parker parker : parkers) { stringBuilder.append(parker.report()); } return stringBuilder.toString(); } }
Parker中的关于report()方法的代码如下:
public String report() { StringBuilder stringBuilder = new StringBuilder().append(TWO_SPACE_INDENT).append("parker:\n"); for (ParkingLot parkingLot : parkingLotList) { stringBuilder.append(parkingLot.info()); } return stringBuilder.toString(); }
ParkingLot中关于report的方法如下:
public String info() { StringBuilder stringBuilder = new StringBuilder() .append(FOUR_SPACE_INDENT) .append("parkinglot:") .append(capacity - spaces + "/" + capacity) .append("\n"); return stringBuilder.toString(); }在完成这个代码之后,有一个不易被发现的Bad Smell,当我们需要修改report的方式的时候,我们需要遍历整个代码结构树上的类,并做出修改。这种情况下,有一个通用的设计模式可以解决这类问题,这就是Visitor模式。即为类层次结构中全部,或部分成员添加一个report方法,该report方法接受一个Report类型的参数(根据需求,可使用不同的实现类),然后,把该成员的report功能委托给Report去做。经过提取参数,pull members up等重构手法对代码拾掇以后,类的层次结构变为:
如果,还有新的需求,我们可以继续通过如上的方法,明确需求-》查找合适的设计模式 -》重构出这个设计模式,保持一个干净的代码环境。
总结:
1、简单设计,以最快的速度实现当前需求
2、TDD保证重构信心
3、模式是重构出来
4、保持对代码异味的高度敏感性
本文中的示例代码地址:https://github.com/xianlinbox/ChessDemo/tree/master/src/main/java/parkinglot
发表评论
-
关于并发的思考
2015-02-08 22:33 4341并发数 并发数和2个因 ... -
使用Hystrix守护应用(3)
2015-01-02 22:04 12879监控HystrixCommand 除了隔离依赖服务的调用外,H ... -
使用Hystrix守护应用(2)
2014-12-30 14:35 16817接上篇(http://ningandjiao.iteye.co ... -
使用Hystrix守护应用(1)
2014-12-30 14:28 15288Hystrix(https://github.com/Netf ... -
Mac下同时安装多个版本的JDK
2014-04-14 21:42 33245JDK8 GA之后,小伙伴们喜大普奔,纷纷跃跃欲试,想体验一下 ... -
性能测试工具之Gatling
2014-01-15 19:27 17300Gatling一直是久闻其名但 ... -
JavaMail测试工具之GreenMail
2014-01-08 19:13 7369不管现在各种Mock框架的运用有多广,我个人在写单元测试的时候 ... -
定制一个Gradle Plugin --- project-structure
2014-01-03 21:23 8496最近在项目中遇到一个 ... -
Restful Spring MVC应用的Request验证
2013-12-26 15:05 23374在开放平台的时候,尤其是坐Rest服务的时候,因为用户可以给你 ... -
Spring MVC中的异常处理
2013-12-25 13:13 24175在一个良好的Rest架构的应用中,所有的异常都应该有对应的Ht ... -
Spring 4.0升级小贴士
2013-12-22 19:40 11442随着Spring4.0的发布,很多同志估计都在考虑升级的事情了 ... -
Spring4.0给我们带来什么?
2013-12-22 17:13 45033JDK8 对JDK8的支持,这个目前来说还是探索性质,毕竟Ja ... -
RESTful API版本控制策略
2013-12-15 19:51 31750做RESTful开放平台,一方面其API变动越少, 对API调 ... -
对象转换利器之Dozer
2013-12-14 22:46 19882在Java的世界中,经常会 ... -
基于Spring-WS的Restful API的集成测试
2013-11-28 19:41 9072在很多Java企业级应用中,Spring占据了非常重要的位置, ... -
TDD Of Spring JMS
2013-11-25 19:53 1760不知何时养成了习惯,在没有一个可运行的测试的时候,个人完全没有 ... -
Micro Service工具集之Swagger:可测试的样式化API文档
2013-09-28 19:55 44743在我之前的一篇博文中,介绍了Yammer开发团队贡献的开源微服 ... -
进击的Java开发
2013-07-14 20:48 5914今天在公司的邮件组中看到一组很有趣的讨论,这是我最喜欢目前公司 ... -
说说SpringBatch的领域概念
2013-06-21 20:32 3627谈到Spring Batch,会谈到 ... -
做项目时需要考虑的安全性问题
2013-04-16 20:20 4787在开发一个项目的时候,大家经常会忽略项目的安全性问题,有很多的 ...
相关推荐
三维重构 可以检测有效的系统缺陷,进行缺陷的定位,缺陷体积的测量等,如何进行三维重构(3D reconstuction)的输入是各种三维以下的数据,比如纯二维的RGB图像(序列)、带有深度信息的RGBD数据等,出来的是三维...
《设计模式》的作者Erich Gamma为本书作序,足见其在软件工程中的重要地位。 书中介绍了超过70种行之有效的重构方法。这些方法是多年来软件开发者在实际工作中逐渐总结出来的经验,目的是为了在不改变系统外部行为...
测试阶段,模型在未见过的数据上评估其泛化能力。 重构过程主要是为了优化实验流程,提高代码的可读性、可维护性和执行效率。这可能包括模块化代码、优化数据处理步骤、调整模型结构以适应更大规模的数据或改进训练...
其次,教学设计应紧密围绕文本,通过精心设计的各个环节,如“导入—创设情境”、“引读—理解文意,理情节”、“细品—看英雄,观天地”、“深悟—知天地,见众生”和“精练—读经典、写人物”,逐步培养学生的速读...
CT系统在不破坏样品的情况下,利用样品对射线能量的吸收特性对生物组织 与工程材料的样品进行断层成像.即通过发射光源的起点然后中间经过...射,然后投影在探测器上面,故在探测器上可以见物质的几个图像与能量的变化.
由官方代码重构而得,本仓库只有推理代码, yolov5的官方代码见:https://github.com/ultralytics/yolov5.git 本API提供检测类型80种,对应索引和类型见下图 img 二、环境说明 见requirements.txt 三、参数说明...
重构,早就不再是“奢侈品”,而是“日用品”。纵然如此,在自己的工作过程中,还是听到很多关于重构的误解。...目前为止,我还没有见过一个程序员,包括我自己在内,写代码是一遍就写得非常整洁,无需重构的
基于C/C++实现将光激励红外结合深度相机,联合机械臂自动扫查扫查系统,实现自动扫查与三维重构+源码+项目文档,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,...
永磁同步电机SVPWM过调制电压重构MTPA弱磁矢量控制仿真 模型 (1)内置式永磁同步电机,搭建基于反馈电压环的弱磁控制MATLAB仿真模型,同时结合...(6)仿真波形见截图。 仿真学习,biye设计好资料,2015B版本以上。
这意味着即使面对未见过的异常情况,模型也能有效地预测和重构数据,这对于实际操作中传感器故障的应对和数据恢复具有重要意义。 总的来说,这项研究展示了深度学习和神经网络在解决复杂热力系统数据问题上的潜力,...
本仓库代码由官方代码重构而得, 官方代码见:https://github.com/zengwb-lx/Yolov5-Deepsort-Fastreid.git 二、环境说明 相关依赖库见:requirements.txt 三、API参数说明 mot.src.deep_reid.DeepReid 行人多...
再分析 A、C 只有前面的一个面不同,根据展开图的关系,当右侧面和上面确定时,前面一定也随之确定,故答案选 C。 例 3:此题答案选 B。解析:此题的两个特征面—涂黑的面,是对面的关系,那只要在其展开图判断该两...
在本文件《现代通信技术之我见》中,虽然没有直接提供详细内容,但从标题和描述中可以看出,文档可能探讨了现代通信技术的各个方面,包括但不限于IP技术、网络架构以及未来发展趋势等。 标题和描述中提及的IP技术,...
《保险业信息化建设之我见》 在当前的数字化时代,保险行业的信息化建设已经成为企业竞争力的关键因素。本文将深入探讨保险行业的现状、发展趋势以及信息化建设的重要性。 保险行业现状与发展趋势: 1. 行业现状:...
0积分下载,代码运行效果图见压缩包 1、完整代码,可直接运行 ,包运行 2、海神之光擅长领域:路径规划、优化求解、神经网络预测、图像处理、语音处理等多种领域Matlab仿真 3、版本:2014a或2019b
各路大小巨头围绕资讯...而随着互联网 C 端人口红利的消失,移动用户增长见顶,移动互联网步入存量市场,C 端用户变现迎来天花板。增长放缓的同时成本进一步推高,同时随着渠道的下沉红利殆尽,C 端流量总量遭遇天花板
【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八) 【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--服务定位器和IoC容器(九) 【SSH进阶之路】...
它打破了传统的以人定岗、以职位定岗的方式,通过科学的流程设计,重构组织架构,以适应企业未来的发展需求,提升管理水平。这一过程需要长期坚持,与业务流程优化相结合,通过管理诊断找到问题,如同医生对症下药,...
测试和重构遗留代码Sandro Mancuso 重构 kata 的 .NET 版本(见链接)。代码 git clone https://github.com/orient-man/TripServiceKata.gitcd TripServiceKatagit checkout demo-start使用 git 导航重构步骤有用的 ...
遵循“见名知意”的原则,使得其他开发者看到方法名就能理解其作用。 3. **内联方法(Inline Method)**:如果一个方法非常短且只在一个地方被调用,可以考虑将其内容直接替换掉调用的地方,减少调用层次,提高执行...