编程笔记
1. 数据结构
1.1 结构拆分
1.1.1 数据层级原则上不宜过深
- 为了方便阅读代码,且保证在查找相关数据结构时,能较快跳转到所定义的文件中,从而进行扩展或修改等操作。
- 同一个文件进行查找或跳转,在一定程度上,会比在多个文件中进行查找跳转更优。
1.1.2 多层基本数据组合而成的数据需要进行合理拆分
- 当存在多层基本数据组合而成的数据时,为了方便理解,需要进行合理拆分及添加相应注释。
struct Data {
groupListMap map[int][][]int
}
// 进行简单拆分
type group []int // 单个组合
type groupList []group // 组合列表
struct Data {
groupListMap map[int]groupList
}
1.2 数据状态
1.2.1 标记or状态值
- 当存在多种标记时,则要考虑是否可以通过状态值来达到多种标记的作用,以减少多种标记字段的维护和提高使用的方便性。
2. 协议相关
2.1 协议设计
2.1.1 功能的统一
- 设计协议时,不代表功能拆分得越细,越容易理解和使用。而是应该将请求和反馈协议,进行配套,避免出现单个请求,而又多种反馈协议的出现,否则会导致理解和使用变得麻烦。
2.1.2 尽量使用向后添加字段来扩展协议
- 在协议的使用上,为了方便理解和使用,而应该尽量使用向后添加字段的方式来扩展协议,不宜通过json字符串将数据保存到一个string类型的字段。
2.2 协议命名
2.2.1 适当使用缩写
- 由于可使用注释,故而在设计协议及其字段时,要保证既能保证命名简单,又能反映出大概用途,则可适当地利用缩写来实现。
- 需要注意的是,单词缩写往往不是简单地截取前几个字母,而应该优先查字典,字典中实在没有的话,则得尽量体现出原有的意思。
3. 代码设计
3.1 优雅设计
- 封装,尽可能掩盖模块内部实现细节,方便进行迭代和替换
- 继承,遵循LSP,非 is-a 或 is-a-kind-of 的关系,而是 hehaves-like-a, is-substitutable-for 的关系
- SRP,一个模块只负责一类事情,有且只有一个被修改的理由
- DIP,高层策略性代码不要依赖实现底层细节,底层细节的代码应该依赖高层策略性代码
- LSP,使用可替换的组件来构建软件系统,同一层次的组件遵守同一个行为约定,以方便替换
- SRP,不要依赖其不直接使用的组件OCP,通过新增代码修改系统行为,而非修改原来的代码
重点:
- 模块一定要隐藏实现细节,只暴露必要接口
- 优先考虑组合,后考虑在行为一致的基础上使用继承
- 高层策略性代码不要依赖实现底层细节,底层细节的代码应该依赖高层策略性代码
3.2 代码层级
- 在使用判断逻辑时,尽量通过使用return、continue或break,来避免代码层级过深二导致阅读困难。
func traversing(v, vals) bool {
if v != nil {
for _,val := range vals {
if val == v {
return true
}
}
}
return false
}
// 可修改为以下方式
func traversing(v, vals) bool {
if v != nil {
return false
}
for _,val := range vals {
if val == v {
return true
}
}
return false
}