1. 防御式编程 Defensive Programming
1.1. 可用、正确和优秀的代码
- 编写大多数情况下都能用(可用)的代码很容易:但是提供意外输入会崩溃。
- 正确的代码绝不会崩溃
- 但所有可能输入集合很大,难以测试
- 并非所有正确的代码都是优秀的代码:可能逻辑难以理解,并且几乎无法维护。
- 优秀的代码是健壮的、高效的、当然也是正确的:即便面对不常见输入,产品级代码也不会崩溃和产生错误的结果。
1.2. 编程中的常见设想
- 这个函数”绝不会”被那样调用:传递给我的参数总是有效的
- 这段代码肯定会”一直”正常运行:它绝对不会产生错误
- 如果我把这个变量标记为”仅限内部使用”,就没有人会尝试访问这个变量
- 进行防御式编程时,不应该做任何设想!
1.3. 你的软件开发过程是怎样的/h2>
- 1 :工作流:可读性差
- 2 :扁平化,缺点是需要明显的控制变量
- 3 :短路,需要做之后的处理
- 4 :合适的
- 5 :异常,异常的处理不明显
3.4. 错误信息编写
- 当需要由用户清理错误时
- 以用户期望的方式呈现信息:“磁盘空间:0KB”/li>
- 确保用户能够理解错误信息
- 不要呈现毫无意义的错误代码:“Error code 707E”/li>
- 将后果严重的错误与仅仅是警告区分开来:可使用”Error:”或图标
- 提示用户每种选择可能的后果后再提出问题:“是否继续”/li>
3.5. 异常
- 是把代码中的错误或异常事件传递给调用方代码的一种特殊手段
- 当遇到意料之外的情况,但不知道该如何处理时,可以抛出一个异常
- 同继承一样,谨慎使用可降低复杂度
- 基本结构
- 子程序使用throw抛出一个异常对象
- 被调用链上层其他子程序的try-catch语句捕获

- 为什么C++没有finally呢为C++提供了资源获得和初始化RAI,确保无论是否发生异常都可以完成清理工作。因为C++可以自己进行析构。
3.5.1. Trace a Program Execution
3.5.2. 使用建议
- 用异常通知程序的其他部分,发生了不可忽略的错误
- 能提供一种无法被忽略的错误通知机制
- 消除了错误向外扩散的可能性
- 只有真正例外的情况下才抛出异常
- 仅在其他编码实践方法无法解决的情况下才使用异常(同断言类似,处理罕见且不该发生的情况)
- 会增加复杂度:调用子程序的代码需要了解被调用代码中可能会抛出的异常,弱化了封装性
- 不能用异常来推卸责任:可以在局部处理就在局部处理掉
- 避免在构造函数和析构函数中抛出异常,除非你在同一地方把它们捕获:C++中,构造函数中的异常会造成资源泄露
- 在恰当的抽象层次抛出异常:确保异常的抽象层次与子程序接口的抽象层次是一致的
3.5.3. 举例
- 抛出的异常也是程序接口的一部分,和其他具体的数据类型一样
- 子程序的调用方代码不是与Employee类的代码耦合,而是与比Employee类层次更低的抛出EOFException异常的代码耦合起来了
3.5.4. 改进
- GetTaxId() 代码应抛回一个与其所在类的接口相一致的异常
- 在设计上需要增加EmployeeDataNotAvailable异常类型,
并将更底层的EOFException异常映射为该异常类型3
3.5.5. 使用建议(补)
- 在异常消息中加入关于导致异常发生的全部信息:确保消息中含有为理解异常抛出原因所需的信息,如数组下标错误
- 避免使用空的catch语句:意味着try或catch里的代码不对
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!