重构,走出重构误区
现在有太多是文章讨论各种重构的技术,咱们就不谈了,我们就谈谈要怎么重构。
一谈到重构,大家大多认为是运用设计模式,来使你的代码看上去非常优雅。其实重构包括很多,一个变量名的修改、代码格式的编排、分解一个大方法的等等都是属于重构的范畴。
我相信肯定有人和我一样,捧一本重构方面的书(《重构与模式》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、增加了系统的复杂度。
这样,如果以后我们再碰到“第一次的代码”,我们就能直接把它重构到“第三次代码”,不用经过“第二次代码”。
想想为什么我们无法写出像书本上那样的优雅的代码,那是因为我们没真正理解问题的所在、找到问题的关键点。必须先经历“第二次代码”,才能到达“第三次代码”。
PS:很高兴得到大家的积极回复、讨论。
对于“第三次代码”中的OrderStatusHelper560889223又再次重构,我个人觉得是一段很精彩的代码,把它在这,提供大家参考。
1 public class OrderStatuHelper
2 {
3 private static readonly Dictionary<OrderStatu, string> enum2string;
4
5 static OrderStatuhelper
6 {
7 enum2string = new Dictionary<OrderStatu, string>();
8 enum2string[OrderStatu.Created] = "Created";
9 enum2string[OrderStatu.Closed] = "Closed";
10 enum2string[OrderStatu.Dealing] = "Dealing";
11 enum2string[OrderStatu.Paying] = "Paying";
12 enum2string[OrderStatu.Posting] = "Posting";
13 }
14
15 public static string GetStatu(OrderStatu orderStatu)
16 {
17 string statuString;
18 return enum2string.TryGetValue(orderStatu, out statuString) ? statuString : enum2string[OrderStatu.Created];
19 }
20 }