当前位置:   article > 正文

代码大全2笔记(持续更新)

代码大全2

代码大全笔记

前言:代码是写给人看的,只是机器恰好能运行而已。

第 II 部分 高质量代码

1. 可以工作的类

1.1 关于构造函数

  • 尽可能的在构造函数中初始化所有的成员数据
  • 使用 private 构造函数来达到强制的单例属性,构造器私有化可以防止创建对象
  • 尽量使用深拷贝而不是浅拷贝
    • 深拷贝:完全复制一个一模一样的对象,与源数据没有关系,不受影响;(通过重写类的 clone() 方法,实现 Cloneable 接口,clone 的同时也要拷贝所有的引用)
    • 浅拷贝:仅复制了对象的引用,如果被拷贝的数据修改,源数据也会修改。浅拷贝通常是为了考虑性能。

1.2 关于继承

  • 尽可能的不要有过深的继承树结构
  • 尽量在类中少用其他类的子程序
  • 通用的数据(字段)和行为(函数)尽量抽取到更高的基类

2.高质量的子程序(方法/函数)

2.1 为什么要创建子程序

  • 降低复杂性 :一个方法总比一大段逻辑看起来要舒服很多
  • 避免代码重复
  • 支持子类化 :可以对子程序进行重写等操作
  • 隐藏处理顺序:调用方无需关心里面执行的顺序
  • 提高可移植性
  • 简化复杂的布尔表达式
  • 提高程序的性能:仅把一段代码放在一个位置更容易发现代码的效率问题;
  • 提升代码的可读性:一个部分的作用抽象为一个方法,通过很好的方法名可以提升可读性
  • 好的代码都是自解的

2.2 子程序的级别设计(内聚的级别)

级别排序为从强到弱

  • 功能性内聚:仅执行一个操作的内聚
  • 顺序性内聚:在内聚中规定了顺序行为,按照特定顺序执行,并且所有的步骤都完成后才能构成一个完整的功能
  • 通信性内聚:都使用了一个数据,但是之间没有关联,就存在通信性内聚
  • 瞬时性内聚:同一时间需要完成多项操作
  • 过程性内聚:按照特定顺序执行

2.3 好的子程序名称

  • 描述子程序能做的一切事情
  • 避免使用无意义、空大、模糊的动词,如:handle、perform、output、Process等
  • 不要用数字来区分子程序名称
  • 很好的描述程序返回的内容
  • 强势动词+对象宾语
  • 准确的使用反义词

2.4 程序的长度

  • 长度控制在 200 行以内,调查证明大于 200 出现问题会增多
  • 平均长度在 100-150 行

2.5使用子程序参数

  • 参数与调用顺序最好一致
  • 如果几个子程序用了相同的参数,这些参数顺序最好一致
  • 如果传递了参数,就必须要使用它
  • 将状态或错误变量放在最后
  • 对有关参数的接口假设进行文档化说明
  • 参数限制在 7 个左右

2.6 特别注意事项

  • 何时使用函数,何时使用过程
  • 检查所有可能返回逻辑路径

3. 防御性编程

你永远不知道程序会做出什么事情来

重点在于防御呢些意想不到的错误

3.1 保护程序,使其免受无效输入的影响

  • 检查源于外部的所有数据的值
  • 检查子程序所有的输入参数值
  • 决定如何处理错误的输入数据
  • 在一开始就不要引入错误

3.2断言

断言允许程序在运行时自检查

  • 用错误处理代码来处理预期会发生的情况,用断言处理永远不应该发生的情况
  • 避免将要执行的代码放在断言中

3.3 错误处理的方法

  • 返回中立值
  • 日志文件记录
  • 返回错误代码
  • 调用错误处理子程序或对象

3.4 异常

  • 使用异常来通知程序中不可以忽略的错误
  • 尽可能了解代码库会抛出的异常
  • 标准化使用异常方式

4. 伪代码编写过程

4.1 类和子程序构建步骤

  • 创建类的常规设计
  • 构建类中的每个子程序
    • 设计子程序
    • 检查设计
    • 编写子程序
    • 检查代码
  • 将类作为一个整体来审查和测试

4.2 伪代码

  • 使用非正式和自然语言来表示
  • 避免使用目标编程语言的语法元素
  • 足够低的层次上写伪代码,几乎可以直接转换成代码

4.3 使用 PPP 构建子程序

PPP(Pesudocode Programming Process) 伪代码程序过程

设计子程序

  • 检查先决条件
  • 定义子程序要解决的问题
  • 命名子程序
  • 决定如何测试子程序
  • 研究标准库中可用的功能,防止功能重复
  • 考虑错误处理
  • 考虑效率问题
  • 研究算法和数据类型(数据结构)
  • 写伪代码
  • 添加好子程序的头部注释

编码子程序

  • 将伪代码转为程序
  • 检查每一步是否需要分解

检查代码

  • 用心检查错误
  • 编译子程序
  • 逐行执行代码 debug
  • 消除子程序中的错误

第 III 部分 变量

5. 变量使用中的常规问题

5.1 简化变量声明

  • 关闭隐式声明
  • 声明所有变量
  • 遵循命名规范 :定义一套命名规范
  • 检查变量名

5.2 初始化变量指南

  • 在声明时初始化每个变量
  • 在靠近首次使用的地方初始化每个变量
  • 尽可能地使用 final: 可以防止该变量初始化后再被赋值,并且 JVM 对 final 修饰的对象有特殊的优化处理
  • 特别注意累加器和计数器
  • 在构造函数中初始化该类的成员数据
  • 对具名常量进行一次初始化
  • 利用好编译器的警告⚠️信息
  • 检查输入参数的合法性
  • 使用预编程工具,初始化工作内存处

5.3 作用域

作用域或可见性,是指变量在整个程序内部的可见和可引用的程度。

  • 变量引用局部化
  • 尽可能地缩短变量的存活时间
  • 缩小作用域的一般原则
    • 在循环之前立即初始化循环中使用的变量
    • 把相关的语句放到一起
  • 开始的时候就严格限制可见性

5.4 数据控制类型

  • 顺序控制类型
  • if else
  • for、while 循环类型

5.5 每个变量只有一个用途

  • 每个变量限于单一用途
  • 避免使用具有隐含含义的变量
  • 确保使用了所有已声明的变量

6. 变量名称的威力

6.1 选择好名称的注意事项

  • 长度要考虑最优 10~16 个字符
  • 作用域决定变量名称
  • 限定符如 total,max,sum 等最好放在最后
  • 名称中常见的对仗词
    • begin/end
    • first/last
    • locked/unlocked
    • min/max
    • next/previous
    • old/new
    • opened/closed
    • visible/invisible
    • source/target
    • source/destinaton
    • up/down

6.2 特定数据类型的命名

  • 循环索引的命名 i、j、k
  • 状态变量的命名
    • 为状态变量取一个比 flag 更好的名称
  • 临时变量的命名 temp 等
  • 布尔变量的名称
    • done(是否完成)
    • error(发生了错误)
    • found(是否找到某个值)
    • success 或 ok (操作是否成功)
    • 尽量使用肯定的名称而不是否定的
  • 枚举类型的命名
    • 通过前缀来实现对枚举的分组
  • 常量的命名
    • 根据常量代表的抽象实体来进行命名,而不是根据所指的数字

6.3 命名规范的威力

  • 规范可以让代码结构化
  • 规范可以让代码在团队学习中更易学习和理解
  • 正式的代码规范是提高代码可读性的“标配”

6.4 Java 语言的非正式规范

  • 命名规范
    • i 和 j 是整数索引
    • 常量全部大写,并用下划线分隔
    • 类名和接口名中每个单词的首字母大写,包括第一个单词
    • 变量名和方法名中的第一个单词小写
    • 除大写的命名外,下划线不作为命名的分隔符
    • 访问器方法使用 set 和 get 前缀

6.5 前缀的标准化

  • UDT 用户自定义类型
  • 语义前缀

6.6 创建可读的短名称

从某种意义上说,变量名称要断,这个要求是计算机发展早期遗留下来的问题

  • 缩写的一般指导原则
    • 标准缩写
    • 删除虚词 and、or、the
    • 可以在单词中间截断
    • 使用重要的单词,不超过三个
  • 缩写说明
    • 不要删除一个字符来达到缩写
    • 缩写保持一致
    • 创建的名称要能够读出来
    • 避免误读或发音错误的组合
    • 使用同义词词典来避免命名冲突
    • 可以创建标准的缩写文档来记录项目中的所有编码缩写

6.7 变量名称避坑指南

  • 避免使用误导性的命名或缩写
  • 避免使用含义相似的命名
  • 避免使用含义不同但命名相似的变量
  • 避免使用发音接近的命名
  • 避免在命名中使用数字
  • 避免单词拼写错误
  • 避免使用易拼错的单词
  • 避免使用自然语言(日常交流语句)
  • 避免使用标准类型、变量和子程序的名字
  • 避免使用易混淆的字符

7. 基本数据类型

7.1 一般的数字

7.2 整型

  • 检查整数除法
  • 检查整数溢出

7.3 字符和字符串

7.4 枚举类型

  • 尽量用枚举代替布尔类型
  • 枚举能够提升可读性
  • 提升可靠性
  • 提升易更改性
  • 使用枚举检查数据的无效性

7.5 具名常量

  • 具名常量类似于变量,只是分配常量后无法修改其值
  • 例如 MAXIMUM_EMPLOYEES = 1000; 而不是直接使用 1000
  • 让变量的含义一眼可见
  • 具名常量的使用要一致

7.6 数组

  • 确保索引都在数组范围内
  • 尽可能地考虑使用容器而不是数组
  • 检查数组边界点
  • 提防索引串扰

7.7 自定义数据类型

  • 以功能导向的方式来命名新创建的类型
  • 用指向预定义类型名称来命名新创建的类型
  • 避免预定义类型
  • 不要定义容易认为是预定义类型的数据类型

8.不常见的数据类型

8.1 结构体

  • 使用结构体能澄清数据关系,将一组数据捆绑在一起

8.2 全局数据

使用全局数据可能带来的问题:

  • 全局数据注意无意的修改
  • 注意可重入代码的问题
  • 全局数据会阻碍代码的复用
  • 数据初始化的顺序可能存在问题

使用全局数据的作用:

  • 保存全局值
  • 模拟全局常量
  • 模拟枚举类型
  • 简化对常用数据的使用
  • 消除流浪数据

非必要,不要使用全局变量

  • 所有的变量在最开始都声明为成员变量,并且赋予其可见范围,除非必要,再将其设置为全局变量
  • 区分好全局变量与类变量

使用访问器子程序来替代全局数据

  • Getter & Setter
  • 在类中隐藏数据
  • 所有的代码通过访问器子程序来操作数据
  • 不要将所有的全局数据都放在一起
  • 将对数据的访问保持在同一抽象层上

降低全局数据的风险

  • 制定命名规范,一目了然
  • 良好的注释列表
  • 不使用全局数据保存中间变量

第 IV 部分 语句

9. 直线型代码的组织

9.1 顺序攸关的语句

有些代码逻辑必须有顺序的前后之分

  • 组织代码,是依赖关系显而易见
  • 子程序的命名要揭示依赖关系
  • 使用子程序参数来解释依赖关系
  • 用注释标注不明确的依赖关系

9.2 顺序无关的语句

有些代码的逻辑没有顺序的前后之分

  • 自上而下的组织代码
  • 把相关的语句分为一组

10. 使用条件语句

10.1 if 语句

  • 普通的 if else 语句
  • 先写代码的正常路径,再写不寻常的情况
  • 基于对相等性的测试正确分支
  • 将正常情况放在 if 中而非 else 之后
  • if 语句后一定要跟一个有意义的语句
  • 尽可能地测试 if 和 else 的正确性
  • 检查 if 和 else 子句是否颠倒
  • 用布尔函数调用简化方法

10.2 case 语句

选择有效的 case 顺序

  • 选择多种方式组织 case 语句针对不同的情况
  • 按照字母或数字顺序进行排序
  • 将正常情况放在最前面
  • 按照频率排列

case 的使用技巧

  • 不要为了使用 case 语句而虚构变量
  • 只用 default 子句来检测正当的默认情况
  • 使用 default 子句来检测错误
  • 避免直通到 case 语句的结尾,明确编码每个 case 的结束

11. 控制循环(迭代控制结构)

11.1 选择循环类型

何时使用 while 循环

如果事先不知道要循环多少次,就用 while 把

  • 在开始出测试
  • 在结尾处测试

何时使用 for 循环

  • 已知循环次数
  • 不需要内部控制的简单活动

11.2 控制循环

进入循环

  • 尽量简化内容
  • 把控制留在循环外部
  • 循环内部的逻辑当做一个子程序
  • 将初始化代码放在循环之前
  • 将 while 用于无限循环
  • 首选 for 循环

处理循环体

  • 避免空循环
  • 只在循环的开头或末尾进行循环内务处理
  • 每个循环只执行一个功能

退出循环

  • 确保循环会终止
  • 使循环结束条件显而易见
  • 避免在循环内部修改索引
  • 避免依赖于循环索引终值的代码,不要在循环结束后使用循环索引的值,索引只用于控制循环次数
  • 考虑使用安全计数器

提前退出循环

  • 在 while 循环中使用 break
  • 警惕其中散布大量的 break 循环
  • 带标签的 break
  • 慎用 break 和 continue

检查端点

  • 循环的关注点通常要有三种情况
    • 第一种情况
    • 随机选择的中间情况
    • 最后一种情况
  • 在脑海中模拟和手动计算

使用循环变量

12. 常规控制问题

12.1 布尔表达式

用 true 和 false 进行布尔测试,而非 1 和 0

  • 将布尔值隐式地和 true 与 false 进行比较

简化复杂的表达式

  • 将复杂的拆分为简单
  • 将复杂的表达式转移到布尔函数中

构建肯定形式的布尔表达式

  • 在 if 语句中将否定判断转为肯定并将 if 字句与 else 字句翻转
  • 用德摩根定理简化否定形式的布尔判断

用括号澄清布尔表达式

  • 使用简单的技术技巧使圆括号对称
    • 当遇到起始括号 " ( " 计数器 +1,遇到括号 " ) " 计数器 -1,最终结尾为 0 则没问题
  • 用圆括号完整描述逻辑表达式

理解布尔表达式如何求值

按照数轴顺序来写数值表达式

  • 符号尽可能的朝向一个方向

和 0 进行比较时的指导原则

  • 隐式比较
  • 将数字与 0 比较
  • 对象类型和 null 进行比较

12.2 复合语句(语句块)

12.3 空语句

  • 避免过多嵌套

12.4 驾驭深层嵌套

  • 将嵌套 if 语句转换为 case 语句
  • 将深层嵌套的代码整理为子程序
  • 可以使用工厂模式来使得过程更面向对象

12.5 编程基础: 结构化编程

结构化变成的核心思想:单进单出的控制结构

break、continue、throw、catch、return

结构化编程的三个组成部分

  • 顺序
    • 即正常的语序结构
  • 选择
    • if switch-case 语句
  • 迭代(循环)

12.6 控制结构与复杂度

  • 尽可能的降低代码复杂度
  • 如何度量复杂度
  • 如何衡量复杂度

第 V 部分 代码部分

13. 软件质量概述

13.1 软件质量的特性

外部特性:

  • 正确性
  • 易用性
  • 效率
  • 可靠性
  • 完整性
  • 适应性
  • 精确性
  • 健壮性

内部特性:

  • 可维护性
  • 灵活性
  • 可移植性
  • 可重用性
  • 可读性
  • 可测试性
  • 可理解性

13.2 改进软件质量的技术

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/246383
推荐阅读
相关标签
  

闽ICP备14008679号