防御式编程
防御式编程应该要检查数据的正确性,以及在出现错误数据时应该如何处理(避免程序崩溃,提示用户,让程序正确的崩溃,处理异常等)。 其核心思想是:子程序不应该因传入错误的数据而被破坏,要承认程序都会有问题,都需要被修改。
保护程序免遭非法输入数据的破坏
检查所有来源于外部的数据
当从文件,用户,网络或其它外部中获取数据时,要检查所有的数据值,以确保值在合法的范围内。
检查输入的参数
- 决定如何处理错误的数据
断言
断言对于大型的复杂程序或可靠性要求极高的程序来说尤其有用。通过使用断言,程序员能更快排查出因修改代码或者别的原因而导致的错误。
- 输入和输出参数处于合理的范围
- 子程序开始(结束)执行时,文件处于打开(关闭)状态
- 文件或流已用只读‘只写或可读写的方式打开
- 仅用于输入的变量没有被子程序所修改
- 指针非空
- 传入子程序的数组或其它窗口至少能容纳X个数据元素
- 表已初始化,存储着真实的数值
断言只是用于开发和维护阶段。
- 用错误处理代码来处理预期会发生的情况,断言来处理绝不应该发生的情况。
- 避免把要执行的代码放到断言中
- 用断言来注解前条件和后条件
- 对于高健壮性的代码,应该先使用断言再处理错误
错误处理技术
当程序中出现错误数据时,可选的处理方式有如下几种
- 返回中立值
- 换用下一个正确的数据
- 返回与前次相同的数据
- 换用最近的合法值
- 把警告信息记录到日志文件中
- 返回一个错误码
- 调用错误处理子程序
- 当错误发生时显示错误信息
- 用最妥当的方式在局部处理错误
- 关闭程序
异常
异常是把代码的错误和异常事件传递给调用方的一种特殊手段。 异常和继承一样要审慎明智的使用。
- 用异常通知程序的其余部分,发生了不可忽略的错误
- 不能用异常来推卸责任
- 避免在构造和析构函数中抛出异常,除非你在同一个地方捕获它们
- 在恰当的抽象层次抛出异常
1 2 3 4 5 6 7 |
|
这个EOFException就和GetTexID的抽象层次不一致,暴露了内部是用读取文件的方式实现的。然而在这个抽象层次,调用方是不关心也不依赖于你是用什么方式实现的。所以正确的做法是再抽象一个Exception。
1 2 3 4 5 6 7 |
|
- 在异常消息中加入导致异常的全部消息
- 避免使用空的catch语句
- 了解所用函数库可能抛出的异常
- 考虑创建一个集中的异常报告机制。 可以自己定制一个异常的机类,里面实现了如何记录异常的方法
- 把项目中对异常的使用标准化
- 考虑异常的替换方案
使用防火墙的隔离技术,在某一层次上统一做数据的检查(数据验证层),下面的层次就可以不用做检查了。
例如在类的public接口统一对传入的参数进行检测,private就不做这些检测了
尽早引入辅助调试的代码和工具
- 计划移除辅助调试代码
- 使用类似ant和make这样的工具
- 使用内置的预处理器 如DEBUG等
- 使用自己编写的预处理器
- 使用调试存根
采用进攻式编程
异常情况应该尽早的在开发阶段让它显现出来。
- 确保断言语句使程序终止运行
- 完全填充分配到的所有内存
- 完全填充已分配到的文件或流
- 确保每一个case语句中的default分支或else分支都能产生严重的错误。