重构的技巧

摘要:
我们应该为下一批露营者改善环境。)这就是为什么我不断重构代码以使其干净整洁。谈到编程质量,代码的可读性是我最重要的部分。我想分享一些我用来简化大多数人不知道的代码的重构技术。字典映射如果您有一个switch语句来分配一些值:switch{casevalue1:result=@“valueFor1”;break;casevalue2:result=@“valueFor2”;break;caseView3:result=@”valueFor3“;break:casevalue4:result=@”valueFor4“;break;case value5:result=@“valueFor5”;breake;default:result ult=@”valueForDefault“;break:}returnresult;请记住,switch只有五个值。想象一下一对多。让我们使用字典映射来简化代码:staticNSDictionary*mapping=nil;If(!我们可以使用block来简化这段代码。最近,我重新构建了一些代码来格式化不同类型的字符串:If{title=[NSStringStringWithFormat:(self.vehicle.numberOfScratches=1?

原文:http://www.cocoachina.com/industry/20140816/9397.html

我想一条童子军的军规:“始终保持露营地比你发现它的时候还要干净”。如果你在地上发现了一点脏东西,不管是谁弄的,都清理掉它。要为了下一拨来露营的人改善环境。(实际上,那条规矩的早期版本,出自Robert Stephenson Smyth Bden-Powell,童子军活动之父,说的是“努力使世界比你发现它时变得更好”。) 这就是为什么我不断的重构我的代码让它干净整洁. 当谈到编程的质量时,代码的可读性是我最关注的部分. 我想分享一些大部分人不知道的我用来简化代码的重构技巧.
 
字典的映射
假如你有一个switch语句来分配一些值:
  1. switch(condition) { 
  2.           case value1: 
  3.               result = @"valueFor1"; 
  4.           break; 
  5.           case value2: 
  6.               result = @"valueFor2"; 
  7.           break; 
  8.           case value3: 
  9.               result = @"valueFor3"; 
  10.           break; 
  11.           case value4: 
  12.               result = @"valueFor4"; 
  13.           break; 
  14.           case value5: 
  15.               result = @"valueFor5"; 
  16.           break; 
  17.           default: 
  18.               result = @"valueForDefault"; 
  19.           break; 
  20.       } 
  21.       return result; 
记住这儿仅仅就 switch 5个值, 想象一下一对多. 让我们使用字典映射来简化这段代码:
  1. static NSDictionary *mapping = nil; 
  2.       if(!mapping) { 
  3.           mapping = @{ 
  4.               @(value1) : @"valueFor1", 
  5.               @(value2) : @"valueFor2", 
  6.               @(value3) : @"valueFor3", 
  7.               @(value4) : @"valueFor4" 
  8.               @(value5) : @"valueFor5" 
  9.           }; 
  10.       } 
  11.   
  12.       return mapping[@value] ?: @"valueForDefault"; 
 
Pro’s(赞成的原因)
1.更方便阅读,即使在原来的switch里面有着更多的值也可以变得更容易阅读.
2.更快,映射仅仅构造一次,然后我们只需要快速的查找值.
3.更不易出错,因为这儿并不需要写break或者return. 4.基于代码映射的性质可以非常轻松的将这个映射转成某种静态数据,例如JSON,PLIST文件,.
 
用block动态映射
 
关于更加复杂的switch,怎么样真正动态的做一些事情?我们可以用block来简化这段代码.
 
最近,我重构了一些代码,字符串格式化来针对不同的类型:
  1. if ([title isEqualToString:@"Scratches"]) 
  2.   { 
  3.       title = [NSString stringWithFormat:(self.vehicle.numberOfScratches == 1 ? @"%d Scratch" : @"%d Scratches"), self.vehicle.numberOfScratches]; 
  4.   } 
  5.      else if ([title isEqualToString:@"Dents"]) 
  6.   { 
  7.       title = [NSString stringWithFormat:(self.vehicle.numberOfDents == 1 ? @"%d Dent" : @"%d Dents"), self.vehicle.numberOfDents]; 
  8.   } 
  9.   else if ([title isEqualToString:@"Painted Panels"]) 
  10.   { 
  11.       title = [NSString stringWithFormat:(self.vehicle.numberOfPaintedPanels == 1 ? @"%d Painted Panel" : @"%d Painted Panels"), self.vehicle.numberOfPaintedPanels]; 
  12.   } 
  13.   else if ([title isEqualToString:@"Chips"]) 
  14.   { 
  15.       title = [NSString stringWithFormat:(self.vehicle.numberOfChips == 1 ? @"%d Chip" : @"%d Chips"), self.vehicle.numberOfChips]; 
  16.   } 
  17.   else if ([title isEqualToString:@"Tires"]) 
  18.   { 
  19.       title = [NSString stringWithFormat:(self.vehicle.numberOfTires == 1 ? @"%d Tire" : @"%d Tires"), self.vehicle.numberOfTires]; 
  20.   } 
  21.   else title = nil; 
 
通过使用 block 映射,我们可以重构这段代码为下面这样:
  1. static NSDictionary *titleMapping = nil; 
  2. if (!titleMapping) { 
  3.  NSString *(^const format)(NSUInteger, NSString *, NSString *) = ^(NSUInteger value, NSString *singular, NSString *plural) { 
  4.     return [NSString stringWithFormat:@"%d %@", value, (value == 1 ? singular : plural)]; 
  5.   }; 
  6.   
  7.   titleMapping = @{ 
  8.     @"Scratches" : ^(MyClass *target) { 
  9.       return format([target numberOfScratches], @"Scratch", @"Scratches"); 
  10.     }, 
  11.     @"Dents" : ^(MyClass *target) { 
  12.       return format([target numberOfDents], @"Dent", @"Dents"); 
  13.     }, 
  14.     @"Painted Panels" : ^(MyClass *target) { 
  15.       return format([target numberOfPaintedPanels], @"Painted Panel", @"Painted Panels"); 
  16.     }, 
  17.     @"Chips" : ^(MyClass *target) { 
  18.       return format([target numberOfChips], @"Chip", @"Chips"); 
  19.     }, 
  20.     @"Tires" : ^(MyClass *target) { 
  21.       return format([target numberOfTires], @"Tire", @"Tires"); 
  22.     } 
  23.   }; 
  24.   
  25.   NSString *(^getTitle)(MyClass *target) = titleMapping[title]; 
  26.   return getTitle ? getTitle(self) : nil; 
Pro’s
1.非常安全,因为没有办法弄错if-else链. 2.缓存了映射,因为我们使用的是静态的变量. 3.我们可以很容易的添加一些宏来使得代码更精简,并且因此更容易来扩展.
 
PS.我可以用字符串匹配来实现它,甚至使用的代码更少. 但是我不认为它能使可读性更好.
 
更早使用 return 和取反 if 的判断条件来简化的流程
现在你大概可能发现我不太喜欢太多的if条件句并且我讨厌太长的if-esle链. 反而我比较喜欢让if条件语句尽可能的简单并且更早使用return来返回.
 
原始代码:
  1. if(!error) { 
  2.   //! success code 
  3. else { 
  4.   //! failure code 
我比较喜欢的写法:
  1. if(error) { 
  2.   //! failure code 
  3.   return; 
  4.   
  5. //! success code 
Pro’s 1.我不需要阅读更多的代码.假如我仅仅只是对error的情况感兴趣.
2.在大段代码的情况我不需要去记住所有的流程,因为我可以非常清楚看到前面的return/break.
 
使用动态方法解决
有时,我们可能看到类似下面的情况:
  1. if([type isEqualToString:@"videoWidget"]) { 
  2.   [self parseVideoWidget:dictionary]; 
  3. else 
  4. if([type isEqualToString:@"imageWidget"]) { 
  5.   [self parseImageWidget:dictionary]; 
  6. else 
  7. if([type isEqualToString:@"textWidget"]) { 
  8.   [self parseTextWidget:dictionary]; 
  9. else 
  10. if([type isEqualToString:@"twitterWidget"]) { 
  11.   [self parseTwitterWidget:dictionary]; 
首先,我可以把上面讲的所有重构技巧应用到此,但是这段代码看起来主要等待解决的问题是将来的可扩展问题,让我们一起看看如何能够让它变得更好.
  1. SEL dynamicSelector = NSSelectorFromString([NSString stringWithFormat:@"parse%@:", type]); 
  2. if(![self respondsToSelector:dynamicSelector]) { 
  3.   DDLogWarning(@"Unsupported widget type %@", type); 
  4.   return; 
  5. [self performSelector:dynamicSelector withObject:dictionary]; 
Pro’s 1.非常容易阅读并且理解 2.比if条件语句更安全 3.更容易扩展,例如我可以添加新的工具类型到分类中.当开发一个衍生APP的时候我甚至都不需要去接触它的基础类.
 
结论
我时常重构我的代码,这儿有一些知道人不多的技巧,但是有助于让你的代码更简化.我通常在“AppCode”上写我的代码.AppCode是一个很棒的IDE,它有着大量的关于重构的函数,我每天都在使用这些,点击链接下载.
 

免责声明:文章转载自《重构的技巧》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇什么是TDD(一)C Primer Plus(十五)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

ios版本更新总结

更新思路,获取APP Store 版本号与项目本地版本号对比,如果本地低于商店版本号,就提示用户更新(说明:在上架项目时请保持本地和商店版本号一致,避免检测更新问题被拒) 1.获取商店版本号,代码如下,其中urlString里的id为APP在商店里的id唯一标示 NSString *urlString = @"http://itunes.apple.com...

WKWebView-b

上一篇文章我们使用了JavaScriptCore框架重写了之前的示例,iOS8苹果偏爱HTML5,重构了UIWebVIew,给我们带来了WKWebView,使其性能、稳定性、功能大幅度提升,也更好的支持了HTML5的新特性。这篇文章就们就拿WKWebView来小试牛刀 回到顶部 一、WKWebView Framework WKWebView的14个类与...

[转]NSString/NSMutableString字符串处理和常用代码 (实例)

Objective-C 中核心处理字符串的类是 NSString 与 NSMutableString ,这两个类最大的区别就是NSString 创建赋值以后该字符串的内容与长度不能在动态的更改,除非重新给这个字符串赋值。而NSMutableString 创建赋值以后可以动态在该字符串上更改内容与长度。  NSString 常用方法总结 +(id)str...

蓝牙硬件交互数据传输Demo

#import "ViewController.h" #import <CoreBluetooth/CoreBluetooth.h> @interface ViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate> /// 中央管理者 -->管理设备的扫描...

iOS websocket

iOS websocket 最近在开发一个直播应用,需要用到弹幕功能,后台说要用websocket来实现,所以学习了一下 一、 RocketSocket搜索了一下发现,用的最多的还是Facebook的RocketSocket库,虽然已经停止维护了,但是还能使用。 创建socket - (SRWebSocket *)webSocket { if...

iOS 数据持久化 NSUserDefault

每一个应用都有一个 NSUserDefaults 实例,向 NSUserDefaults 类发送 standardUserDefaults 消息可以得到该实例。 NSUserDefaults 实例类似与 NSMutableDictionary,可以通过键存取或删除该对象。 当应用第一次使用 NSUserDefaults 实例时,NSUserDefaults...