现在有太多是文章讨论各种重构的技术,咱们就不谈了,我们就谈谈要怎么重构。
一谈到重构,大家大多认为是运用设计模式,来使你的代码看上去非常优雅。其实重构包括很多,一个变量名的修改、代码格式的编排、分解一个大方法的等等都是属于重构的范畴。
我相信肯定有人和我一样,捧一本重构方面的书(《重构与模式》Joshua Kerievsky著,这本就不错),一劲的狂喊这样写代码太漂亮;可是丢开书本,面对自己的代码一直寻找可以运用设计模式、需要重构的代码,最后发现一处可重构的都没。 写出优雅的代码,相信对于很多人来说一直是个瓶颈、很难去突破。不过突破后,你会发现你的世界变大了,犹如跳出井口的青蛙。
那我们到底才能写出那么优雅的代码呢。我们先说说,我们的重构误区吧。
误区:
1、从已有的代码寻找与书本中匹对一样或类似的场景。
2、在编写新代码时,脑子一直想着那几种模式,想去套用,一直想用上几个。
最终还是没什么好的消息,造成这样的原因是,你没真正的理解设计模式的运用场景、重构技术。
也许心里面会对自己说,这是项目比较小,没出现书本提到的那些场景。
其实重构你可以从以下几个方面入手。
2、review自己的代码,如果觉得不好的地方就想想有没有更好的方法。可以拿出来和别人讨论,相信你一定有不一样的收获。
3、让别人review自己的代码。在团队开发中,难免其他队员开发的功能,会和你这边的模块有关联,当有队员来问你这个函数实现什么功能、这段代码的什么意思。
这有可能以下的原因:a、自己写的代码太烂! b、队员的技术太菜,看不懂。 c、队员较懒,不想去看。
在给他解释时,你就要注意你们的对话,对你重构是有帮助的。
队员:我不懂你这个变量是干什么的。
你就要想想,自己写变量命名不规范?
队员:你这段太长了,看得我头痛。
也是你的函数真的太长了,该修剪你的代码了,把这个大功能,分割为几个小功能。
4、阅读别人的代码。你可以阅读一些比较经典的开源代码,这样你可以和很多人一起讨论。在阅读时,要认认真真的看,读懂它的框架,渗透理解它的各个细节。
下面我举一个我在现实开发中碰到的一个问题:
第一次代码:
1 public class OrderSync 2 { 3 //订单状态,Created、Closee、Dealing、Paying、Posting 4 public string Status; 5 public void Sync() 6 { 7 OrderRequest req=new OrderRequest(); 8 req.Status=Status; 9 10 req.Search(); 11 ... 12 } 13 } 14 15 OrderSync orderSync=new OrderSync(); 16 orderSync.Status = "Created";
缺点:
1、不清楚订单有哪几种状态。
2、如果“Created”,改成为“Create”,需要修改所有的地方,那你就开始寻找吧。
3、orderSync.Status = "Created";不小心写成orderSync.Status = "Created1111";只能单独纳闷为什么无法查询到记录。
第二次代码:
1 public class OrderSync 2 { 3 //订单状态,Created、Closed、Dealing、Paying、Posting 4 public string Status; 5 public void Sync() 6 { 7 OrderRequest req = new OrderRequest(); 8 req.Status=Status; 9 10 req.Search(); 11 ... 12 } 13 } 14 15 public class OrderStatu 16 { 17 public static string Created = "Created"; 18 public static string Closed = "Closed"; 19 public static string Dealing = "Dealing"; 20 public static string Paying = "Paying"; 21 public static string Posting = "Posting"; 22 } 23 24 OrderSync orderSync = new OrderSync(); 25 orderSync.Status = OrderStatu.Created;
此次重构解决了第一次的3个缺点。但它还是有缺点的:
1、在OrderSync中Status是字符串的,没相应的格式来限制。若你的团队来了一个新的成员,他对此系统不是很熟悉,他就有可能这么写: OrderSync orderSync = new OrderSync(); orderSync.Status = "Created";
第三次代码:
1 public class OrderSync 2 { 3 public OrderStatu Status; 4 public void Sync() 5 { 6 OrderRequest req=new OrderRequest(); 7 req.Status = OrderStatuHelper.GetStatu(Status); 8 9 req.Search(); 10 ... 11 } 12 } 13 14 public enum OrderStatu 15 { 16 Created, 17 Closed, 18 Dealing, 19 Paying, 20 Posting 21 } 22 23 public class OrderStatuHelper 24 { 25 private static string Created = "Created"; 26 private static string Closed = "Closed"; 27 private static string Dealing = "Dealing"; 28 private static string Paying = "Paying"; 29 private static string Posting = "Posting"; 30 31 public static string GetStatu(OrderStatu orderStatu) 32 { 33 switch(orderStatu) 34 { 35 case OrderStatu.Closed: 36 return Closed; 37 case OrderStatu.Dealing: 38 return Dealing; 39 case OrderStatu.Payding: 40 return Pading; 41 case OrderStatu.Posting: 42 return Posting; 43 default: 44 return Created; 45 } 46 } 47 }
这样在给订单赋值时,只能从OrderStatu去选择状态,避免了第二次的缺点。
当然了它也是有缺点的:
1、性能相对于第一次不是很高。(在性能差的系统中,这往往不是影响系统性能的主要原因)
2、增加了系统的复杂度。
这样,如果以后我们再碰到“第一次的代码”,我们就能直接把它重构到“第三次代码”,不用经过“第二次代码”。
想想为什么我们无法写出像书本上那样的优雅的代码,那是因为我们没真正理解问题的所在、找到问题的关键点。必须先经历“第二次代码”,才能到达“第三次代码”。