随着软件行业的不断发展,历史遗留下来的程序越来越多,代码的维护成本越来越高,甚至大于开发成本。新功能的开发往往依赖于旧代码,阅读旧代码所花费的时间几乎大于编写新功能代码的时间。前几天看了一本书。书中有一句话:“复杂的代码往往是新手写的,只有经验丰富的高手才能写出简单而富有表现力的代码”。夸张了,但也说明了经验的重要性。我们写的代码除了要被机器执行外,还需要别人阅读。所以我们要写:Codethatcanbereadytoothersscalablecodetestablecode(代码应该是可测试的,为不可测试的代码写测试是浪费生命)其中,第2点和第3点更为强调关于面向对象的设计原则。本文更侧重于本地代码问题。本文以实例的方式总结了常见的错误和优化方法。本文中的示例基于两个指导原则:1.DRY(Don'trepeatyourself)这个原则如此重要,仅仅是因为:代码越少,bug越少没有重复逻辑的代码更容易维护,当你修复如果发现了bug,如果在另外一个地方出现了同样的逻辑,而你却没有意识到,你是不是觉得很委屈?2.TED原则简洁(Terse)、表现力(Expressive)、只做一件事(Doonething)。@#$??%^&^&*((!@#$%^&^&*((!@#$%^&^&*((!@#$%^&^&*((//////publicdecimalGetCash(){//!@#$%^&^&*((!@#$%^&^&*((vara=newList(){2m,3m,10m};varb=2;varc=0m;//!@#$%^&^&*((!@#$%^&^&*((!@#$%^&^&*((foreach(varpina){c+=p*b;}returnc;}重构后:publicdecimalCalculateTotalCash(){varprices=newList(){2m,3m,10m};varitemCount=2;returnprices。Sum(p=>p*itemCount);}好的代码命名完全可以代替注释的作用,如果你在尝试写注释,从某种角度来说,你就是在尝试写一段别人写不出来的代码理解。当你不能给你的方法一个准确的名字时,很可能你的方法做了不止一件事而违反了(Doonething)。尤其是当你想在方法名中添加And、Or、If等词时2.给一个布尔变量赋值反例:publicboolIsAdult(intage){boolisAdult;if(age>18){isAdult=true;}else{isAdult=false;}returnisAdult;}重构后:publicboolIsAdult(intage){varisAdult=age>18;returnisAdult;}3.双否定条件判断反例:if(!isNotRemeberMe){}重构后:if(isRemeberMe){}不管你有没有见过这样的条件,反正我有。看到这样的条件判断,我顿时晕了过去。4、拒绝HardCode,拒绝挖坑反例:if(carName==“Nissan”){}重构后:if(car==Car.Nissan){}既然玩的是强类型语言,那就用编译吧5.拒绝幻数,拒绝挖坑反例:if(age>18){}重构后:constintadultAge=18;if(age>adultAge){}所谓幻数(Magicnumber)就是一个魔法数字。读者无法弄清楚你的号码是多少。这种代码往往见得比较多。=JobState.Submitted||job.JobState==JobState.Expired||job.JobTitle.IsNullOrWhiteSpace()){//....}重构后:if(CanBeDeleted(job)){//}privateboolCanBeDeleted(Jobjob){varinvalidJobState=job.JobState==JobState.New||job.JobState==JobState.Submitted||job.JobState==JobState.Expired;varinvalidJob=string.IsNullOrEmpty(job.JobTitle);returninvalidJobState||invalidJob;}是不是有什么顿悟?7、否定判断示例:varisValid=false;if(!string.IsNullOrEmpty(user.UserName)){if(!string.IsNullOrEmpty(user.Password)){if(!string.IsNullOrEmpty(user.Email)){isValid=true;}}}returnisValid;重构后:if(string.IsNullOrEmpty(user.UserName))returnfalse;if(string.IsNullOrEmpty(user.Password))returnfalse;if(string.IsNullOr空(user.Email))返回false;返回真;第一段代码的灵感来自早期的一些想法:用一个变量来存储返回结果结果发现应该在知道结果的时候就返回。8.使用前提反例:if(!string.IsNullOrEmpty(userName)){if(!string.IsNullOrEmpty(password)){//register}else{thrownewArgumentException("userpasswordcannotbeempty");}}else{thrownewArgumentException("usernamecannotbeempty");}重构后:if(string.IsNullOrEmpty(userName))thrownewArgumentException("usernamecannotbeempty");if(string.IsNullOrEmpty(password))thrownewArgumentException("userpasswordcannotbeempty");//register重构后的样式更接近contract编程,必须先满足前置条件,否则就没有必要了。9.参数过多,反例多于3个:publicvoidRegisterUser(stringuserName,stringpassword,stringemail,stringphone){}重构后:publicvoidRegisterUser(Useruser){}参数过多,读者难以把握代码意图,而过多的参数会影响方法的稳定性。此外,它还表明应该将参数聚合到一个Model10中。方法签名包含一个布尔参数反例:publicvoidRegisterUser(Useruser,boolsendEmail){}重构后:publicvoidRegisterUser(Useruser){}publicvoidSendEmail(Useruser){}布尔参数告诉方法不仅要做一件事,还违反做一件事事情10。编写富有表现力的代码反例:privatestringCombineTechnicalBookNameOfAuthor(Listbooks,stringauthor){varfilterBooks=newList();foreach(varbookinbooks){if(book.Category==BookCategory.Technical&&book.Author==author){filterBooks.Add(book);}}varname="";foreach(varbookinfilterBooks){name+=book.Name+"|";}returnname;}重构后:privatestringCombineTechnicalBookNameOfAuthor(Listbooks,stringauthor){varcombinedName=books.Where(b=>b.Category==BookCategory.Technical).Where(b=>b.Author==author).Select(b=>b.Name).Aggregate((a,b)=>a+"|"+b);returncombinedName;}与命令式代码相比,声明式代码更具表现力和简洁性。这也是函数式编程越来越流行的原因之一。4.关于DRY通常大家在重构代码的时候,一个重要的思想就是DRY。我想分享一个DRY反例:项目在架构过程中会存在各种MODEL层,比如:DomainModel、ViewModel、DTO。很多时候,这些模型中的大部分字段都是相同的,所以有人会想到DRY原则,干脆直接使用一个类型,省去粘贴、复制、来回转换的麻烦。这个反例失败的根本原因是这些模型的职责不同。虽然在大多数情况下内容是重复的,但它们所起的作用是不同的。考虑这种情况:DomainModel有一个字段DateTimeBirthday{get;set;},ViewModel也有DateTimeBirthday{get;set;}。需求升级:要求界面不再显示生日,只显示是否成人。我们只需要在ViewModel中添加一个BoolIsAdult{get{return....}}即可,DomainModel根本不需要改动。5.使用高级制作工具以vs插件中的Reshaper为例。对于本文列出的大部分反例,Reshaprer都可以给出不同程度的提示。经过一段时间的练习,当Reshaper无法给你的代码任何提示的时候,你的代码就会有明显的提升。截图显示了Resharper的提示功能:将光标移动到波浪线上,然后Alt+Enter,Resharper会自动优化代码。如果你能避免本文总结的反例,你的代码就已经具备了优秀代码该有的基因。当然,高质量的代码还需要良好的设计和面向对象编程的原则。如果你想了解更多,请阅读《代码大全》、《代码整洁之道》、?、《敏捷软件开发 原则、模式与实践》