适合自己的才是最好的。以下内容参考《编写可读代码的艺术》一书,同时加入了自己的思考和总结。
可读性是衡量代码质量的一个核心指标,追求减少代码行数固然重要,更关键的是要减少他人理解代码所花费的时间。
1. 让命名承载信息
命名应当直观表达其用途,使阅读者见名知意。优秀的命名等同于一条注释,可以传递大量信息。
- 使用领域专业术语:如加密领域里的 encrypt, decrypt, signature 等。
- 避免口语化:比如使用 init 代替 start,register 代替 new 等。
- 使用行业公认缩写:如公钥 PK 、私钥 SK。
- 使用有意义的代称:尽量避免直接使用 data、result 等泛化词汇,可以增加上下文信息,使名称更具体,如 userInfo、validatedResult。
- 变量名中包含单位或格式:如使用 timeoutInSeconds 代替 timeout,十六进制编码字符串 hexStr。
- 使用前后缀区分不同层级数据:如 _ 前缀用于局部变量,与全局变量区分。
- 合理控制长度:小作用域内变量名可以使用简写或缩写,不用包含太多信息。
- 避免语义重复:如 convertToString 可简化为 toString。
- 统一风格:一般驼峰用于变量名和方法名,下划线用于常量名或文件名、表名等特定属性。
- 消除歧义:确保名称含义清晰,如 min 和 max 包含极限值,begin 和 end 适合范围,表示起点与终点,start 和 finish 适合过程,表示启动和结束。
- 明确布尔值:如使用 is、has、need、can、use 等前缀,避免使用双重否定,如 disable = fasle 可能需要绕一圈才能明白是否禁用。
1.1. 命名规范建议
- 类名:多为名词,更多的是体现其职责,如 UserController、UserService、EncryptHelper、DataUtils 等。
- 接口名:多为形容词或描述功能的词,更多是体现其能力,如 Serializable、 Runnable、Callable 等。
- 方法名:多为动词或动宾结构,清晰表达方法的操作,如 CURD 命名、validateData、isAvailable 等。
2. 审美与格式化
- 合理使用留白、对齐、换行、分组,让代码逻辑有一定的结构感。
- 保持风格一致:如限制行长为 100 个字符。
- 有意义的顺序:参数、方法、变量按重要性排列,避免乱序,同时不要在此处是 ABC ,在另外一个地方是 CBA 。
- 按逻辑相关性分组:用空行分隔代码块,使结构清晰。
3. 编写有效注释
- 注释不仅仅是描述代码的作用,更多的是帮助阅读者了解设计意图。
- 避免冗余注释:易懂的代码无需额外注释。
- 避免不佳命名的注释:替换不清晰的命名,而非用注释弥补。
- 记录思考过程:特别是使用了设计模式和复杂算法的地方。
- 过期的注释比没有注释更麻烦:更新代码的同时,不要忘记更新注释。
- 标记任务:使用 TODO-待完成, FIXME-有问题待修复, XXX-待改进等标识标记代码。
- 高层次注释:概述类间交互和数据流向。
- 摘要性注释:非复杂逻辑,只需表达代码目的而非细节。
4. 简化控制流程
过多的条件判断、循环、嵌套会让代码变得混乱,应保持流程简洁、线性。
- 逻辑顺序:一般条件语句中让左侧为变量,右侧为常量,利于理解,如 length > 0 比 0 < length 更自然。
- 正向逻辑优先:正向判断是大多数业务逻辑的主流写法,例如非空值执行流程,空值处理逻辑则作为补充。
- 三元表达式:适合简单的判断逻辑,如果出现三元表达式嵌套,建议转成 if/else 。
- 避免使用 do/while:因为至少会执行一次,通常情况下,判断条件应该出现在执行代码之前。
- 拆分复杂表达式:使用解释性变量,将复杂的表达式分解为小块。
- 布尔表达式优化:根据需要取反或简化逻辑表达式。
- 局部声明:变量应尽量在使用前声明,减少顶端统一声明造成混乱。
关于判断是否为 nul l的写法
判断是否为 null 表达式,到底是 user == null 还是 null == user ?
使用 null == user 写法,是为了避免遗漏一个 =, 变成赋值 user = null,但现在的开发工具或编译器可以检查出这种语法错误,并进行错误提示;同时 user == null 更符合阅读逻辑,因为我们想知道 user 是否为 null,而不是 null 是否等于 user。
5. 命名模式总结
这些模式借鉴了 Spring、Netty 等开源代码的命名方式。明确定义各类职责和使用场景。
类型 | 含义 | 适用场景 | 示例 |
---|---|---|---|
Bootstrap / Starter | 启动器 | 程序或模块启动 | ServerBootstrap |
Processor | 处理器 | 用于处理特定功能或逻辑 | MessageProcessor |
Manager | 管理器 | 用于对象生命周期或资源管理 | TransactionManager |
Provider | 提供者 | 用于提供某类服务或接口实现 | ServiceProvider |
Register | 注册器 | 用于注册资源或服务 | EventRegister |
Helper | 辅助类 | 封装简单功能 | StringHelper |
Context | 上下文 | 参数传递容器 | ApplicationContext |
Callback | 回调 | 异步任务后的操作 | RetryCallback |
Parser | 解析器 | 数据解析 | JsonParser |
Validator | 校验器 | 用于检查数据的合法性 | DataValidator |
Formatter | 格式化器 | 数据格式化 | DateFormatter |
Converter | 转换器 | 类型转换 | NumberConverter |
Selector | 选择器 | 选择合适的对象或数据 | FileSelector |
Generator | 生成器 | 用于生成特定对象或数据 | TokenGenerator |
Initializer | 初始化器 | 用于初始化,通常在加载前执行 | BeanInitializer |
Pool | 对象池 | 资源的复用管理 | ThreadPool |
Action | 动作 | 表示一种可执行的动作 | UserAction |
Command | 命令 | 封装操作或请求 | LoginCommand |
Component | 组件 | 可独立使用的单元 | UserComponent |
Cache | 缓存 | 保存数据的缓存类 | MemoryCache |
Metric | 度量 | 用于性能或数据统计 | CacheMetric |
Template | 模板 | 常用于定义操作步骤 | JdbcTemplate |
Builder | 构建器 | 用于构建复杂对象 | StringBuilder |
Factory | 工厂 | 用于创建对象的类 | ConnectionFactory |
Strategy | 策略 | 实现特定策略的算法接口或类 | SortStrategy |
Task | 任务 | 需要调度执行的单元 | ScheduledTask |
Trigger | 触发器 | 调度或规则控制的触发条件 | CronTrigger |
Scheduler | 调度器 | 控制任务调度的模块 | TaskScheduler |
Event | 事件 | 用于通知系统状态发生变化的事件 | UserEvent |
Listener | 监听器 | 用于监听事件 | EventListener |
Publisher | 发布者 | 用于发布消息或事件 | EventPublisher |
Subscriber | 订阅者 | 用于接收发布者发送的数据 | MessageSubscriber |
Handler | 事件处理器 | 用于处理接收到的消息或事件 | NotificationHandler |