代码命名与代码结构语义性
代码命名
具体性
- 描述性:变量名应清楚地表明其含义,如
userAge,totalPrice。 - 简洁性:尽量简洁,但不牺牲清晰性,例如
num而非numberOfItemsInCart。 - 避免缩写:除非非常常见,如
id代表identifier。
避免误导性
免使用负面条件:尽量避免在变量和函数名中使用否定词汇
不要使用容易混淆的命名:避免使用容易与其他变量、函数或类混淆的名称,尤其是在相同的代码范围内。
免使用负面条件:尽量避免在变量和函数名中使用否定词汇,如 notFound,因为这些可能导致逻辑上的双重否定,使得代码阅读起来更加困难。
不要隐瞒副作用:如果函数或方法有副作用(如修改全局状态、执行I/O操作等),应在命名中体现出来,避免给出没有副作用的印象。
专业性
选择专业的词汇,避免泛泛的名字
- 相对于
make,选择create,generate,build等词汇会更有表现力,更加专业。 - 相对于
find,选择search,extract,recover等词汇会更有表现力,更加专业。
给名字附带更多信息(上下文无法区分时)
- 为变量添加单位
- 为变量添加重要属性
决定名字最适合的长度
- 如果变量的作用域很小,可以取很短的名字
- 驼峰命名中的单元不能超过3个
- 不能使用大家不熟悉的缩写
- 丢掉不必要的单元
控制流
使用符合人类自然语言的表达习惯
写代码也是一个表达的过程,虽然表现形式不同,但是如果我们能够采用符合人类自然语言习惯的表达习
惯来写代码,对阅读代码的人理解我们的代码是很有帮助的。
这里有两个比较典型的情景:
- 条件语句中参数的顺序
- 条件语句中的正负逻辑
使用声明式
声明式代码是指使用合适的代码结构和命名规范来描述代码的逻辑和功能,使得代码的结构和内容更加清晰明了,有利于代码的阅读和维护
代码结构
对象结构
符合现实世界模型
字段和属性
- 参考: 代码命名
方法
-
动词-对象格式: 方法名应该清楚地描述它们的行为,通常遵循动词-对象格式。例如,
calculateTotal或printDocument。 -
清晰的参数: 方法的参数应明确且有意义。例如,
sendEmail(to, subject, message)比sendEmail(arg1, arg2, arg3)更清晰。 -
单一职责原则: 每个方法应只执行一个功能。这使得方法名能更清楚地描述其功能。
-
模拟真实世界对象: 你的对象应尽可能地模拟真实世界的对象。这有助于理解对象的用途和行为,借助自然语言描述来将想法变成代码。
- 取值的方法(Getters):
- 命名通常以
get开头,后跟要获取的属性名(首字母大写)。 - 例子:
getName(),getAge(),getAddress()。
- 命名通常以
- 设置值的方法(Setters):
- 命名通常以
set开头,后跟要设置的属性名(首字母大写)。 - 例子:
setName(String name),setAge(int age),setAddress(String address)。
- 命名通常以
- 执行操作的方法:
- 使用动词或动词短语来清晰描述方法执行的操作。
- 例子:
save(),delete(),calculateTotal(),printReport()。
- 布尔值检查的方法:
- 对于返回布尔值的方法,命名通常以
is,can,has等开始,表示一个状态或能力的查询。 - 例子:
isEmpty(),isAvailable(),hasChildren()。
- 对于返回布尔值的方法,命名通常以
- 转换类型的方法:
- 表示类型转换的方法通常以
to开头,后跟目标类型。 - 例子:
toString(),toArray(),toMap()。
- 表示类型转换的方法通常以
- 工厂方法:
- 用于创建对象的方法,通常以
create,make,build等开头。 - 例子:
createUser(),makeConnection(),buildResponse()。
- 用于创建对象的方法,通常以
- 初始化和清理的方法:
- 用于初始化和清理的方法,通常以
init,setup,destroy,cleanup等命名。 - 例子:
initialize(),setUp(),destroyInstance(),cleanUpResources()。
- 用于初始化和清理的方法,通常以
- 事件处理的方法:
- 用于事件处理的方法,常以
on开头,后跟事件名称。 - 例子:
onClick(),onDataReceived(),onError()。
- 用于事件处理的方法,常以
- 处理异常的方法:
- 专门用于处理错误和异常的方法。
- 常以
handle开头,如handleError,handleException。
事件
- 描述事件本身: 事件名称应描述事件本身,而不是事件的结果。例如,
onClick或onDataReceived。 - 使用常见约定: 遵循常见的事件命名约定,例如
on<Event>格式。
- 创建和销毁事件
- 创建事件:通常使用
onCreate,onInitialize,onConstructed等。 - 销毁事件:常用
onDestroy,onDispose,onDeallocate等。
- 状态改变事件
- 属性更改:使用
on[Property]Changed,例如onNameChanged,onStatusUpdated。 - 状态转换:使用
on[State]To[NewState],例如onActiveToInactive。
- 用户交互事件(GUI 编程中常见)
- 点击事件:使用
onClick,onPress,onSelect。 - 悬停事件:使用
onHover,onMouseEnter,onMouseLeave。 - 键盘事件:使用
onKeyPress,onKeyDown,onKeyUp。
- 数据操作事件
- 数据加载:使用
onDataLoad,onDataFetch,onDataReceived。 - 数据保存:使用
onDataSave,onDataUpdate,onDataPersist。
- 通信事件
- 消息发送:使用
onMessageSend,onDataSent。 - 消息接收:使用
onMessageReceived,onDataReceived。
- 错误和异常事件
- 错误发生:使用
onError,onFailure,onException。 - 异常捕获:使用
onExceptionCaught,onErrorHandled。
- 自定义事件
- 自定义事件:根据事件的具体作用和上下文,使用描述性的名称,例如
onAttack,onMove,onHealthDecrease。
对象关系
- 关联(Association):
- 定义:两个不同类的对象相互连接。关联可以是单向的或双向的。
- 例子:一个
Teacher对象与多个Student对象相关联,代表教师教授这些学生。
- 例子:一个
- 命名习惯:使用描述性的名词或短语,清晰表达实体间的关系。
- 例子:如果一个
Employee类与Department类关联,你可能会在Employee类中有一个department属性。
- 例子:如果一个
- 定义:两个不同类的对象相互连接。关联可以是单向的或双向的。
- 聚合(Aggregation):
- 定义:一种特殊的关联,表示“拥有”或“整体-部分”关系,但组成部分可以独立于整体存在。
- 例子:一个
Department对象包含多个Employee对象,但这些Employee对象可以存在于Department之外。
- 例子:一个
- 命名习惯:通常表示为集合,名字应反映集合的性质。
- 例子:在
Department类中,可能有一个employees属性,表明部门包含多个员工。
- 例子:在
- 定义:一种特殊的关联,表示“拥有”或“整体-部分”关系,但组成部分可以独立于整体存在。
- 组合(Composition):
- 定义:比聚合更强的关联形式,表示更严格的“拥有”关系。在组合中,部分与整体的生命周期是一致的。
- 例子:一个
Car对象包含多个Wheel对象。如果Car对象不存在了,那么这些Wheel对象也不会独立存在。
- 例子:一个
- 命名习惯:通常表示为强烈的拥有关系,名字应体现这种关系。
- 例子:在
Car类中,可能有一个属性名为engine,表明每辆车都有一个发动机。
- 例子:在
- 定义:比聚合更强的关联形式,表示更严格的“拥有”关系。在组合中,部分与整体的生命周期是一致的。
- 继承(Inheritance):
- 定义:表示一种“是一个”关系。它使得子类可以继承父类的属性和方法。
- 例子:
Cat类和Dog类可以继承自更一般的Animal类。
- 例子:
- 命名习惯:子类的名称应当反映其与父类的关系,常用“是一个”(is-a)的关系描述。
- 例子:
Dog类继承自Animal类,表明每个Dog“是一个”Animal。
- 例子:
- 定义:表示一种“是一个”关系。它使得子类可以继承父类的属性和方法。
- 依赖(Dependency):
- 定义:一种使用关系,其中一个类的变化影响到另一个类。
- 例子:如果一个
Calculator类的方法需要使用MathUtility类,那么Calculator依赖于MathUtility。
- 例子:如果一个
- 命名习惯:方法参数或局部变量名应清晰地指出其类型和用途。
- 例子:一个计算类(如
Calculator)的方法可能接受一个MathUtility类的实例作为参数,名为mathUtil
- 例子:一个计算类(如
- 定义:一种使用关系,其中一个类的变化影响到另一个类。
- 实现(Implementation):
- 定义:通常用于接口和实现该接口的类之间的关系。一个类实现一个接口,需要实现接口定义的所有方法。
- 例子:一个
Car类可以实现一个Vehicle接口,表明Car类提供了Vehicle接口的所有方法。
- 例子:一个
- 命名习惯:接口名通常是形容词或以 “-able” 结尾的名词,实现类的名称应反映其功能。
- 例子:接口名为
Runnable,实现该接口的类可能被命名为TaskExecutor。
- 例子:接口名为
- 定义:通常用于接口和实现该接口的类之间的关系。一个类实现一个接口,需要实现接口定义的所有方法。
效果
团队的新成员是否能迅速理解这个变量名的含义
在整个项目中保持命名的一致性