跳转至

整洁代码

  • 让读的过程便轻松,即使编写过程困难

有意义的命名

名副其实

==命名必须有意义== - 模糊度:上下文在代码中未被明确体现的程度

避免误导

  1. 避免留下掩藏代码本意的错误线索,避免使用与本意相悖的词
  2. 提防使用不同之处较小的名称

做有意义的区分

通过区分提供不同的信息

使用读的出来的名称

  • 方便口头表述

使用可搜索的名称

  • 虽然长但方便检索和辨别

避免使用编码

避免思维映射

  • 明确是王道

类名

  • 名词

方法名

  • 动词

每个概念对应一个词

  • 函数名称应该独一无二并且保持一致

别用双关语

使用解决方案领域名称

  • 尽量使用术语、算法名、模式名、数学术语

使用源自所涉问题领域的名称

添加有意义的语境

  • 单独出现的state与添加了语境后单独出现的addrstate
  • 更好的方案:创建名为Address的类

不要添加没用的语境

函数

短小

  • 每个函数都只说一件事
  • 每个函数都依序把你带到下一个函数
  • 避免过多的缩进和嵌套循环

只做一件事

  • 函数应该做一件事,做好这件事
  • 要判断函数是否只做了一件事,就看是否能再拆除一个函数

每个函数一个抽象层级

抽象层次 - ryelqy - 博客园 - 要确保函数只做一件事情,函数中的语句都要在同一抽象层级上 - 代码清单3-7

switch语句

  • 确保每个switch都埋藏在较低的抽象层级,并且永不重复
  • 利用多态来实现

使用描述性名称

  • 描述函数所做的事
  • 别害怕长名称
  • 别害怕花时间取名字
  • 描述性的名称能够理清关于模块的设计思路
  • 命名方式保持一致

函数参数

  • 最理想:零参数
  • 不太期望信息通过参数输出(利用面向对象可以一定程度上避免)

一元函数的普遍形式

  1. 询问有关参数的问题
  2. 操作该参数
  3. 如果函数要对输入参数进行转换操作,转换结果应该体现在返回值

标识参数

  • 丑陋不堪,破坏了函数单个抽象层级

二元函数

  • 自然的组合或自然的排序
  • 尽量利用一些机制将二元转换为一元

三元函数

参数对象

  • 如果函数需要三个以上的参数,则说明这些参数需要封装成类

无副作用

分隔指令与询问

  • 函数要么做什么事,要么回答什么事

==使用异常替代返回错误码==

  • 使用异常代替返回错误码,错误处理代码就能从主路径代码中分离
  • 抽离try/catch代码块,,独立形成一个函数
  • 使用异常替代错误码,新异常就可以直接从旧异常中派生出来

如何写出这样的函数

  • 粗稿:冗长而复杂
  • 打磨:
    • 分解函数
    • 修改名称
    • 消除重复
    • 保持测试通过

注释

  • 注释的作用:弥补在用代码表达意图时遭遇的失败
  • 把力气放在书写清楚代码
  • 不准确的注释比没有注释坏的多

注释不能美化糟糕的代码

  • 写注释的动机之一:糟糕代码的存在
  • ==把代码弄干净!!==
  • ==花时间清洁糟糕的代码==

用代码来阐述

好注释

  1. 法律信息
  2. ==提供消息==的注释
    1. 注释某个抽象方法的返回值
    2. 尽量利用函数名称传达消息
  3. 对意图的解释
  4. 阐释:
    1. 把晦涩难懂的参数或返回值的意义翻译为某种刻度的形式
  5. 警示
  6. ==TODO注释==
    1. 程序员认为应该做而还没做的事
    2. 定期查看,删除不再需要的
  7. 放大
    1. 放大某种看来不合理之物的重要性
  8. 公共API中的Javadoc

坏注释

  1. 喃喃自语
    1. 如果决定写注释,就花时间写最好的注释
  2. 多余的注释
  3. 误导性注释
  4. 循规式注释
  5. 日志式注释
  6. 废话注释
  7. 废话
  8. 能用函数或变量时就别用注释
  9. 位置标记
  10. 括号后的注释
  11. 归属与署名
  12. 注释掉的代码
  13. HTML注释
  14. 非本地信息
    1. 如果一定要写注释,确保它描述了离他最近的代码
  15. 信息过多
  16. 不明显的关系

格式

垂直格式

概念间垂直方向上的区隔

  • 每组代码行展示一条完整的思路
  • 每个空白行都是一条线索,标识出新的独立概念

垂直方向上的靠近

  • 靠近的代码行暗示了他们之间的紧密关系

垂直距离

  • 关系密切的概念应该互相靠近
  • 变量声明:变量声明应该尽可能靠近其使用的位置
    • 循环中的控制变量应该总是再循环语句中声明
  • 实体变量应该在类的顶部声明
  • 若某个函数调用了另外一个,就应该把他们放到一起
    • 调用者应该尽可能放在被调用者之上
  • 概念相关的代码应该放到一起
    • 相关性越强,彼此之间的距离就应该越短
    • 即使没有互相调用,也应该放在一起

横向格式

  • 在赋值操作符周围加上空格字符,达到强调的目的
  • 不再函数名和左圆括号之间添加空格,表明函数与其参数密切相关
  • 空格字符的另一种用法:强调其前面的运算符
  • 乘法因子之间没有空格,表明高优先级

对象和数据结构

数据抽象

  • 以最好的方式呈现某个对象包含的数据

数据、对象的反对称性

  • 过程式代码
    • 在不改动既有数据结构的前提下添加新函数
      • 难以添加新的数据结构,因为必须修改所有函数
  • 面向对象式代码
    • 在不改动既有函数的前提下添加新类
      • 难以添加新函数,因为必须修改类

得墨忒耳律

  • 模块不应了解它所操作对象内部的情形
  • 类C的方法f只应该调用以下对象的方法
    • C
    • 由f创建的对象
    • 作为参数传递给f的对象
    • 由C的实体变量持有的对象

数据传送对象

  • 只有公共变量、没有函数的类
  • 数据库通信、

错误处理

  • 错误处理非常重要,但如果它搞乱了代码逻辑,就是错误的做法

使用异常而非返回码

  • 遇到错误时,最好抛出一个异常

先写Try-Catch-Finally语句

  • try是事务
  • catch将程序维持在一种持续的状态

使用不可控异常

  • 可控异常的代价:
    • 违反开闭原则
  • 如果异常可控,函数签名就要添加throw子句

给出异常发生的环境说明

  • 抛出的每一个异常,都应当提供足够的环境说明,一边判断错误的来源和处所
  • 创建信息充分的错误消息,并且和异常一起传递出去
  • 传递足够的信息给catch块,并且记录下来

依调用者需要定义异常类

通过打包调用API、确保它返回通用异常类型->简化代码

别返回null值

  • 如果打算在方法中返回null值,不如抛出异常,或是返回特例对象
  • 如果在第三方API中可能返回null值的方法,可以考虑用新方法打包这个方法

别传递null值

除非API要求你向他传递null值,否则就要尽可能避免传递null值