代码优化的方法

上一篇博客说到最近做了一个大一些的需求,等需求完成后代码非常的凌乱,自己重构(整理了一波),在整理过程中,有一点对于如何优化代码的想法,特此记录一下。

这里说的优化,是指完成了杂乱的代码后,重现让它更合理,更干净一些,并不是在编程开始前的设计优化,因此不着重于设计模式等的使用。

在代码的review过程中,推荐使用一些gitlab,gerrit等工具来查看自己的代码,因为git工具会将你的代码改动更加直观的展示出来,而在编译器中,我们看到的更多是整体的代码,容易分散注意力。

代码的乱,乱在哪里,一是程序本身的属性不够好,如扩展性,健壮性等。二是可读性不够好,不能很直观的读懂代码。下面是针对这两个方面的几个小方法。

程序本身的提高

思考需求本身,优化设计

这一步其实很重要,因为好的设计可从根本上提高代码的质量,但是因为过于有“个性”,每个项目都有自己适合的设计,无法具体分析。

但是在编码完成后,可以暂时忘掉细节代码,想一下整体的项目需求,套用一下基本的设计模式,比如最简单的工厂模式,观察者模式等等,如果真的有很合适的,千万不要畏惧额外的工作量,改他!

提取共性

这一步其实非常的简单,把代码中使用到的实体类,各种类的属性看一下,有没有一些重合度很高的?比如有一个手机类,一个牙刷类,他们都有一个属性叫做出厂日期预计使用时长,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Phone {

String model;
int useTime;
String createDate;
}

public class Toothbrush {

String size;
int useTime;
String createDate;
}

这个时候就应该考虑是否将这两个属性提取出来,作为基类的存在,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

public class Product {

int useTime;
String createDate;
}

public class Phone extends Product {

String model;
}

public class Toothbrush extends Product {

String size;
}


这样看上去是不是好多了?

在思想上:手机和牙刷都属于产品,产品会有出厂日期和使用时长等属性。

在代码上:这样看上去也会整洁一些。

也许有的朋友会说了,这样看起来改变不是很大呀?值得折腾一下吗?

试想一下当后续拥有1w个产品呢?2w呢?每个类都写这两个属性会多多少代码呢?

代码归位

这一点是我今天主要改动的一些地方,总是编码的过程中不自觉的陷入面对过程编程,然后一溜儿的代码就写出来了,其实都不是很符合面对对象的设计。

还是上面的例子,现在我们要检查一下一个手机使用时间过长了没?来决定能否对他进行二次回收。我们在service层写了一个方法如下:

1
2
3
4
5
6
7
8
9
//测试,没有纠结具体实现及参数类型
//传入日期和手机,判断手机是否过期,过期则返回空,不过期则返回该手机
public Phone huishou(String date, Phone phone) {
String phoneLastDate = phone.createDate + phone.useTime;
if (date.compareTo(phoneLastDate) > 0) {
return null;
}
return phone;
}

看起来是不是特别没有毛病,我们先计算出了该手机可以被使用的最后一天,然后和传入的日期比较来决定是否回收。。。。

但是这样每次回收都需要写一遍比较的这个方法,好歹封装个方法啊(我开始的做法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//测试,没有纠结具体实现及参数类型
//传入日期和手机,判断手机是否过期,过期则返回空,不过期则返回该手机
public Phone huishou(String date, Phone phone) {
if (isOverTime(date,phone)){
return null;
}
return phone;
}

//判断是否过期封装为函数
public boolean isOverTime(String date, Phone phone) {
String phoneLastDate = phone.createDate + phone.useTime;
return date.compareTo(phoneLastDate) > 0;
}

这样子将判断的过程封装为函数,每次回收的时候调用一下这个函数,来决定是否回收就好了。这样多个后手函数也只用这一个函数,省了好多代码!

我真机智!!!!

其实还可以把这个函数写成泛型,凡是继承Product的类都可以判断,又省了一波代码,但是这不是这里的重点,不再展开了。。。

我开始就走到了封装这一步,觉得自己很机智,后来一想,这个方法应该存在于这里吗?手机有出厂日期和使用时间长度的属性,就应该有是否过期的参数或者方法来告诉使用手机的人(或者对象)呀,这个是不是放在手机自身,甚至放在Product基类里面更合适呢?

像这样:

1
2
3
4
5
6
7
8
9
10
11
12
/基类
public class Product {

int useTime;
String createDate;


public boolean isOverTime(String date) {
String productLastDate = createDate + useTime;
return date.compareTo(productLastDate) > 0;
}
}

判断是否回收变成了这样:

1
2
3
4
5
6
7
8
//测试,没有纠结具体实现及参数类型
//传入日期和手机,判断手机是否过期,过期则返回空,不过期则返回该手机
public Phone huishou(String date, Phone phone) {
if (phone.isOverTime(date)) {
return null;
}
return phone;
}

这时候的思想是:拿到手机和日期,问手机:你过期了没!!按照手机的回答决定要不要抛弃(回收)他。

这一步其实涉及到面对对象的设计,其实说起面对对象,我们很多人都可以头头是道,封装,集成,balabala,但是在实际的编码过程中?我们真的有遵守面对对象的思想吗?我们的代码真的可以称得上是面对对象吗?

我不确定,我今天才发现这一点,那我以往的代码应该有很多犯了类似的错误了。

代码可读性

清理变量

虽然我们在编码过程中已经注意变量的定义,但是毕竟当时心系代码,总有疏漏,所以检查一遍总是没错的!

  1. 多个类都使用的静态变量分类移至Constant类中,单个类使用的静态变量自己定义。

  2. 能够定义成final的变量尽量定义成final,倒不是为了效率之类高深的东西,而是为了不下修改导致程序出错。

  3. 查看一下变量名,这个其实应该在编码的时候就注意到,我们要保证自己的变量命令符合规范,而且尽量见名知意。

  4. 不要使用任何的魔法数字(出去内层循环),如 int color = 2;
    应该定义为:

1
2
3
public static final int COLOR_RED = 2;
int color = COLOR_RED;

这样方便后续修改,也方便其他程序员阅读。

添加注释

当你回首看自己的代码,如果有任何地方稍有困惑,而且不修改的话,那就意味着这里需要注释,因为你自己写的都会困惑,其他人应该就蒙了.

如果你的代码足够好,有自解释能力,那么是不需要添加注释的,但是对于普通人来说,我们还是应该在名称不够好的变量,方法上添加注释。

尤其是对外提供的接口以及协议文件如proto里,注释尽可能详细些,否则你会不断地被联调接口的人打扰!

暂时就想到这么多啦!后续有合适的再进行添加。

完。





ChangeLog

2018-09-29 完成

以上皆为个人所思所得,如有错误欢迎评论区指正。

欢迎转载,烦请署名并保留原文链接。

联系邮箱:huyanshi2580@gmail.com

更多学习笔记见个人博客——>呼延十