《代码大全》笔记 2 - 创建高质量的代码

豆瓣:https://book.douban.com/subject/1477390/

《Code Complete》2d ed,CC2

目录

第 5 章 软件构建中的设计

设计中的挑战

关键的设计概念

设计构造块:启发式方法

设计实践

对流行的设计方法的评论

核对表:软件构造中的设计

第 6 章 可以工作的类

抽象数据类型

良好的类接口

良好的封装

有关设计和实现的问题

创建类的原因

第 7 章 高质量的子程序

创建子程序的正当理由

在子程序层上设计

好的子程序名字

如何使用子程序参数

第 8 章 防御式编程

保护程序免遭非法输入数据的破坏

断言

错误处理技术

异常

隔离程序,使之包容由错误造成的损害

辅助调试的代码

第 9 章 伪代码编程过程

创建类的步骤

创建子程序的步骤

使用伪代码设计子程序

基于伪代码编写子程序的代码


第 5 章 软件构建中的设计

设计中的挑战

  • 设计是一个险恶的问题
    • 你必须首先把这个问题“解决”一遍以便能够明确地定义它,然后再次解决该问题,从而形成一个可行的方案。
  • 设计是个了无章法的过程
  • 设计就是确定取舍和调整顺序的过程
  • 设计受到诸多限制
  • 设计是不确定的
  • 设计是一个启发式过程
  • 设计是自然而然形成的

关键的设计概念

  • 软件的首要技术革命:管理复杂度
    • 把任何人在同一时间需要处理的本质复杂度的量减到最少。
    • 不要让偶然性的复杂度无谓地快速增长。
  • 理想的设计特征
    • 最小的复杂度
    • 易于维护。设计自明的(self-explanatory)系统
    • 松散耦合
    • 可扩展性
    • 可重用性
    • 高扇入。让大量的类使用某个基础的工具类。
    • 低扇出。一个类尽量少地使用其他多个类。
    • 可移植性
    • 精简性。删除所有可以删除的代码。
    • 层次性。在一个层次观察代码时不需要牵扯到其它层。
    • 标准技术。不轻易创造新的东西增加理解、学习成本。
  • 设计的层次
    • 软件系统
    • 分解为子系统或包
    • 分解为类
    • 分解成子程序

设计构造块:启发式方法

  • 启发式方法,也即是一些思考问题的方法。类似于数学领域的《怎样解题》。
  • 找出现实世界中的对象。也即是面向对象设计方法。
  • 形成一致的抽象。使用抽象层次处理问题复杂度。
  • 封装实现细节。抽象是以更高层次的细节来看待对象,而封装是着重实现不能看到不该看的细节的效果。
  • 当继承能简化设计时就继承。
  • 隐藏秘密(信息隐藏)。这是比封装更大范围的设计方法。包括隐藏复杂度和变化源。
  • 找出容易改变的区域。并隔离限定起来。
  • 保持松散耦合。特别注意不容易觉察的“语义上的耦合”。
  • 查阅常用的设计模式。

设计实践

  • 分而治之。分解,各个击破。
  • 自上而下和自下而上的设计方法。分别对应从高层次抽象开始和从细节向一般性延伸。
  • 建立试验性原型。试验性意味着,当完成了回答特定设计问题后,代码可以扔掉。
  • 合作设计。

对流行的设计方法的评论

  • 请把设计看成是一个险恶的、杂乱的和启发式的过程。不要停留于你所想到的第一套解决方案,而是去寻求合作,探求简洁性,在需要的时候做出原型,迭代,并进一步迭代。

核对表:软件构造中的设计

  • 你尝试用多种方案来分解系统,以确定最佳方案吗?
  • 为解决某些特定的问题,你对系统中的风险部分或者不熟悉的部分创造过原型、写出数量最少的可抛弃的代码吗?
  • 你的设计方案被其他人检查了吗?
  • 程序是不是易于维护?
  • 设计是否精简?设计出来的每一部分都绝对必要吗?
  • 设计中是否采用了标准的技术?是否避免使用怪异且难以理解的元素?

第 6 章 可以工作的类

  • 软件开发技术的发展,先是直接基于语句来思考编程问题,然后发展到基于子程序来思考,到现在是基于类来思考。

  • 类是由一组数据和子程序构成的集合,这些数据和子程序共同拥有一组内聚的、明确定义的职责。

抽象数据类型

  • 抽象数据类型(ADT,abstract data type)是指一些数据以及对这些数据所进行的操作的集合。
  • 可以隐藏实现细节。

  • 改动不会影响到整个程序。

  • 让接口能提供更多信息。

  • 更容易提高性能。

  • 让程序的正确性更显而易见。

  • 程序更具自我说明性。

  • 无需在程序内到处传递数据。

  • 可以基于高层抽象操作实体,不用关注细节。

良好的类接口

  • 类的接口为隐藏在其后的具体实现提供了一种抽象。
  • 如果类的接口不能展现出一种一致的抽象,那该类的内聚性就很弱。

  • 接口不应只基于语义表达而设计,应基于可编程设计,即编译器能识别并强制实施接口的意图。

良好的封装

  • 尽可能限制类和成员的可访问性。
  • 不要公开暴露成员数据。

  • 避免把私用的实现细节放入类的接口中。

  • 不要对类的使用者做出任何假设。

  • 避免使用友元类。

  • 警惕从语义上破坏封装性。有时上帝视角是坏事。

有关设计和实现的问题

  • 包含(has a)才是面向对象编程中的主力技术,而非继承。
  • 类的数据成员数量最好不要超过 7 个。

  • 继承适用于“是一个……”(is a)的关系。

  • 继承遵循里氏替换原则。

  • 避免让继承体系过深。

创建类的原因

  • 为现实世界中的对象建模。
  • 为抽象的对象建模。

  • 降低复杂度。

  • 隔离复杂度。

  • 隐藏实现细节。

  • 限制变动的影响范围。

  • 隐藏全局数据。

  • 让参数传递更顺畅。

  • 建立中心控制点。

  • 让代码易于重用。

第 7 章 高质量的子程序

创建子程序的正当理由

  • 降低复杂度。
  • 引入中间的、易懂的抽象。

  • 避免代码重复。

  • 支持子类化。方便在派生类中覆盖单一功能。

  • 隐藏实现细节。

  • 提高可移植性。

  • 隔离复杂度。

  • 提高代码重用。

在子程序层上设计

  • 对子程序而言,内聚性是指子程序中各种操作之间联系的紧密程度。
  • 内聚性的多个方面:功能、执行顺序、数据共享、临时集合的操作、按参数决定执行的逻辑分支。

  • 对各种内聚性的的一般处理方法是,按其最小独立模块划分,进一步提高内聚性。

  • 子程序的内部也可以只通过其他子程序进行来实现其功能,即,在子程序层上设计编码。

好的子程序名字

  • 描述子程序所做的所有事情。
  • 避免使用无意义的、模糊或表述不清的动词。

  • 不要仅通过数字来形成不同的子程序名字。

  • 使用合适的子程序名字,9 ~ 15 个字符为佳。

  • 函数命名要对返回值有所描述。

  • 对于过程类子程序使用动词加宾语的形式。

  • 合适的情况使用对仗词。

如何使用子程序参数

  • 按照输入-修改-输出的顺序排列参数。
  • 把有类似参数的多个函数的参数保持一致的顺序。

  • 把状态或出错变量放到最后。

  • 不要把参数变量当做临时变量使用。

  • 对参数有限定条件的情况需明确说明。注释、assert 等。

  • 参数限制在 7 个以内。

  • 采用命名前缀等方法标识参数的输入、修改、输出的属性。

  • 参数的设计需配合子程序接口抽象定义的设计。

第 8 章 防御式编程

  • 在防御式驾驶中要建立这样一种思维,那就是你永远也不能确定另一位司机将要做什么。你要承担起保护自己的责任,哪怕是其他司机犯的错误。

保护程序免遭非法输入数据的破坏

  • 要做到“垃圾进,什么都不出”、“垃圾进来,出去是错误提示”或“不许垃圾进来”。

断言

  • 用错误处理代码来处理预期会发生的状况,用断言来处理绝不应该发生的状况。
  • 避免把需要执行的代码放到断言中。

  • 用断言来注解并验证前条件和后条件。确保调用子程序前的条件和调用后的结果。

  • 断言在发布的产品中关闭,必要时在断言后补充错误处理。

错误处理技术

  • 返回中立值。默认的异常结果。
  • 换用下一个正确的数据。

  • 返回与前次相同的结果。

  • 换用最接近的合法值。

  • 记录异常到日志。返回自定义错误码。

  • 调用统一的错误处理子程序。

  • 关闭程序。

异常

  • 异常是把代码中的错误或异常事件传递给调用方的一种特殊手段。
  • 异常用于报告发生了不可忽略的错误。

  • 在真正例外的情况抛出异常,能预期能处理的当场处理完毕。

  • 不能用异常来推卸责任。

  • 避免在构造和析构函数中向上层抛出异常。

  • 抛出的异常注意其抽象层次与当前子程序一致。

隔离程序,使之包容由错误造成的损害

  • 加入中间处理层,清洗外部进入的异常数据。内部就可以从容使用断言和异常机制。

辅助调试的代码

  • 开发期间牺牲一些速度和对资源的使用,换取可以让开发更顺畅的内置工具。
  • 进攻式编程(Offensive Programming)。专门应用于开发阶段,加速暴露错误的发生,促进处理解决。

第 9 章 伪代码编程过程

  • 伪代码编程过程是创建类和子程序的最佳方法。其他的方法还有,测试先行开发(测试驱动开发),重构,契约式设计。

  • “伪代码”这个术语是指某种用来描述算法、子程序、类或完整程序的工作逻辑的、非形式的、类似于英语的记法。

  • 伪代码编程过程则是一种通过书写伪代码而更高效地创建程序代码的专门方法。

创建类的步骤

创建子程序的步骤

使用伪代码设计子程序

  • 定义子程序要解决的问题。
  • 为子程序命名。

  • 决定如何测试子程序。

  • 在标准库中搜寻可用的功能。避免重复造轮子。

  • 考虑错误处理。

  • 考虑效率问题。设计算法和数据结构。

  • 编写伪代码。

  • 检查伪代码。考虑整体设计,是否有更优方案。在伪代码这一阶段即进行代码改进。

基于伪代码编写子程序的代码

  • 写出子程序的声明。
  • 把伪代码转变为高层次的注释。

  • 在每条注释下面填充代码。

  • 检查代码是否需要进一步分解。重构代码。

2020年11月12日

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页