第二十五计:函数体最多不超过100行
记得以前看过一个函数有9000多行,很壮观啊,从那以后看到长函数时也不奇怪了,我认为过长函数的主要缺点是:
1、严重影响代码的阅读,使用到某个变量的地方可能间隔几百甚至上千行,如果if-else嵌套层次较多的话那就更噩梦了。
2、不利于代码的重用,短小而独立的逻辑处理单元更容易被重用,而过长的代码段则需要经过进一步分解才行。
我觉得函数最好不要超过100行,对于过长的函数要尽可能地进行分解,如果实在不能分解,那么就通过注释的方式增加该函数处理步骤的说明,例如:
public void foo(){ // 1、验证参数、内部状态的有效性 ... // 2、开始倾斜角度 ... // 2.1 计算角度1 ... // 2.2 计算角度2 ... // 3、输出计算说明书 ...
}
第二十六计:使用语言的修饰符确保变量的不可变性
当声明一个变量时,如果能十分确定该变量不会被修改或者不应该被修改,那最好把它声明为不可变的,如使用Java中的final、C++中的const修饰符,这样可以防止本该不变的变量被意外地修改。
第二十七计:对象状态共享
大量对象的同时存在会占用系统宝贵的内存,如果这些对象中某些状态是相同的,那么可以将这些状态提取出来让所有需要它的对象共享,这可以大大减少冗余对象,从而达到节省内存的目的,设计模式中的Flyweight模式可以解决这个问题。
第二十八计:用对象代替普通常量
由于普通常量本质上是一个简单的数字或者字符串,当我们错误地将某个类别的常量在另一个类别的常量的场景中使用时,就会产生问题,但是编译器并不会提示有错误,所以,这可能是一个不小的隐患,例如:
// 表示用户状态的常量声明 public static int USER_STATE_ACTIVE = 0; public static int USER_STATE_DELETE = 1; // 表示用户角色的常量声明 public static int USER_ROLE_NORMAL = 2; public static int USER_ROLE_MANAGER = 3; // 下面用户是否被激活的判断 if(userState == USER_ROLE_NORMAL){ }
这个判断本应该使用USER_STATE_ACTIVE和USER_STATE_DELETE两个常量之一,却意外地使用了其他常量,可能直到Bug产生后才能被发现。
可以使用对象常量来避免这种情况,例如:
public class State{ private int state; public State(int s){ state = s; } } // 表示用户状态的常量声明 public static State USER_STATE_ACTIVE = new State(0); public static State USER_STATE_DELETE = new State(1); public class Role{ private int role; public Role(int r){ role = r; } } // 表示用户角色的常量声明 public static Role USER_ROLE_NORMAL = new Role(2); public static Role USER_ROLE_MANAGER = new Role(3);
下面的判断是无法通过编译的,因为userState是State类型的。
if(userState == USER_ROLE_NORMAL){ }
第二十九计:查询函数中尽量不要有修改操作
我们一般都是根据函数的名字来判断它的功能,“表里不一“的函数可能会引起一些问题,例如我们调了一个查询函数(获取类的成员变量值的函数):getName(),但是它内部却修改了其他成员变量的值,当查找Bug的原因时,很可能会忽略这个函数,从它的名字看,觉得它不会引起问题,到最后发现就是它捣的鬼,心里估计会骂这个函数的作者:他奶奶的,代码如其人,表里不一!
第三十计:尽量封装对象的创建过程
本文之前曾提到过要尽量为成员变量增加set和get函数,主要目的是为了掌握成员变量的控制权,对象的创建过程也是如此,如果提供者掌握了对象创建过程的控制权,那么就可以屏蔽具体的实现类,并且任意修改对象的创建过程。