Posted on 2005-12-10 14:17
小李飞刀 阅读(263)
评论(0) 编辑 收藏
老话题了,自己收集总结了一下
代码调试排错通常是一个痛苦的过程,至少我是这么认为的:-)。对开发人员而言,其实可以在设计和编码时期加以控制,以提高代码质量,
减少后期工作压力。
下面粗略列举一些应该注意的问题,详细内容建议参考JTest的规则,以及DBC -- Design By Contract 规则。
JAVA设计和编码过程中应该注意的几个问题:
1. 不要把问题推迟到运行时刻,尽可能地在编译时暴露问题
这是个原则性问题,对所有的语言都是一样的,强类型语言的出现就是这个原则的一个体现。
a. 如果某个方法需要抛出异常,在方法的定义中就让它抛出,利于编译时检查,否则调用者如果忘记捕获异常,编译时也不会得到提示,
错误将延迟到运行时刻,难以调试处理。
b. 形参的存取控制,如果不希望在方法中改变参数所引用的对象,可以用final对该参数进行限制,这样编译器就会帮你检查。(其实Java
中对参数加上final修饰并没有什么实际用处,因为JAVA使用passed by value方式来传递参数,因此切记不要期望在方法内对参数赋值能
使调用者获得新的对象)。
c. 避免含义模糊的参数,尽量不要为了方便而使用像Hashtable,Vector这样含义模糊的集合类(Collection)参数来传递对象,除非在不
得已的情况下才使用,但一般而言,使用抽象类的数组,以及通过良好的类层次结构设计是可以做到避免集合(Collection)类的使用的。
凡事总有例外,一些模式例如工厂模式有时候需要折衷处理这个问题,为了框架代码不至于因为子类的增加而被频繁修改,有时候不得不把
问题延迟到运行时刻处理。
2. 尽可能地在一个方法中只做一件事,如果方法实在比较复杂,尽量把它分割成合适的几个辅助方法, 内聚和耦合的原则同样适用于小方法
的设计,大架构,小方法可以带给程序更好的可维护性和可测试性,同时也可以提供更多的可复用代码,如果系统结构需要调整时,这一优势
将会非常明显,复杂的方法和纠缠不清的逻辑除了扔掉重来外别无它法。
方法定义应该言行一致,方法名称就应该完全说明这个方法是干什么的。
3. 接口或方法的存取控制问题,接口应该尽可能地简单,不必让调用者知道的方法,应该用private修饰符;提供给子类继承的用
protected修饰,只有需要提供给外部调用的方法才允许用public,默认为包内可见但最好少用.
4. 属性的存取控制,原则上讲,除了接口的常量定义外,一般不允许使用public修饰,需要提供给子类控制的用protected,其他用
private,特别注明,默认为包内可见(有点类似C++的friendly),尽可能明确标记其访问权限,不要含糊地使用大的范围。
5. 使用接口还是类来定义常量, 原则上是尽量使用接口,这样可以减少运行时的内存使用,运行时JVM可能也少耗费资源(需要确认),
至少一个可信的理由就是JDK提供的一些内部使用的常量定义都是在接口中定义的:-)。interface中的成员和方法默认都是public, JTest
规则中对在Interface中的定义加public修饰符会报错,个人觉得没有必要,应该明确标记比较好。
6. 出错时或重要逻辑点打印出尽可能详细的信息,包括当前操作信息,一些参量的值,最好还有代码的位置信息,很多问题难以重现,及时
捕捉并打印出详细的调试信息有助于尽快解决故障。
7. 分开处理和集中控制的折衷, 虽然应该尽可能地按照事务或业务的需要分开处理,但对一些用来调整和控制整个系统的定义量最好集中
控制,系统的性能方面应该尽可能做到可调整的(tunable).
8. 代码重构 代码重构是一个渐进的,永远的过程,只要代码的生命还没有结束,就需要不断的改进,逐步地提炼出公用的东西,将基础支持
部分从应用中剥离出来同时就是在准备下一个应用的开发;代码结构和逻辑逐步变得更加清晰,可维护性和可测试性也在逐步提高,更重要的是
代码改进的同时,开发人员也在同步改进和提高。
9. Self-documented Coding 尽量在代码中用注释说明当前代码的处理逻辑和一些应该注意的问题,特别是一些特殊的处理细节,除了注释外
软件产品的其他地方似乎没有合适的位置保存这类信息。
10. Self-test 代码,比较重要的单元自测代码跟被测试代码保存在一起比较合适,避免代码间关系复杂化,保持单元间的独立性
11. 尽可能少地生成对象,特别是大对象; 虽然硬件速度的提高能够加快Java代码的执行,但过多的使用内存使得Java程序普遍较慢,并且
经常使得系统无法同时运行其他任务。 String类使用方便,但是频繁使用拼接( + )操作会带来很多的临时String对象,需要多次拼接形成
String时,应该考虑用StringBuffer.append()方法代替。对大系统而言,应该有可调整的策略来干预控制垃圾回收。
12. 尽可能地减少嵌套类和内部类的使用,杜绝局部类的使用,匿名类只用于监听器(XXXListener)。
13. 不要使用太多的参数,可以考虑用一个类来封装参数,但参数类也不能难以构造,如果出现这种问题,建议重新考虑设计是否合理。
14. 命名,尽量使用有意义的名称来定义成员变量,方法名,常量,方法参数名称也非常重要。
15. 文档, JavaDoc文档应该尽量清楚,对于提供给开发人员使用的库,其对应JavaDoc应该详细到开发时在集成工具中使用而不必再参考其
他文档的程度,具体包括方法的目的,出参、入参的限制、变化,以及对类的状态的影响,参见DBC的@pre 和@post条件。