一、程序设计
- 程序设计是针对在软件实现中的某些问题进行专门的代码结构方案设计的活动
- 常见的程序设计问题有:
- 可复用性:多个模块或功能是否可共用同一个程序代码单元
- 稳定性:某个代码单元受外部影响的因素是否最少
- 可扩展性:某个代码单元或模块是否能容易地实现新需求
- 易理解性:代码的结构和逻辑是否能容易读懂和维护
- 耦合性:代码单元或模块之间的耦合度是否较低
- 运行效率:代码的执行时间或空间资源使用是否较少
- 安全性:代码是否能够抵抗外部的攻击或威胁等
1、面向对象设计的原则(SOLID)
- S:Single Responsibility Principle,单一职责原则
- O:Open/Close Principle,开放/闭合原则
- L:Liskov Substitution Principle,Liskov替换原则
- I:Interface Segregation Principle,接口隔离原则
- D:Dependency Inversion Principle,依赖倒置原则
一个模块或类应仅有一个引起其变化的因素
换句话说,一个模块或类应该只实现一个或一种类型的业务职责
- 好处
使类或模块更加独立和稳定
也能方便地实现复用 - 缺点
设计类爆炸
类的封装性破坏
2、开放/闭合原则
类或模块的代码对扩展是开放的,对修改是关闭的
当出现新需求时,只通过扩展已有的代码进行实现,而不是修改已有的代码
- 好处
可扩展性好
稳定性高 - 缺点
可读性差
代码测试困难
3、 Liskov替换原则
代码设计中的子类对象能够完全替换掉其父类对象,而不需要改变父类的任何属性
客户端使用子类对象或父类对象,不需要提供额外的信息
- 好处
规范地使用继承
可扩展性好
稳定性高 - 缺点
限制了继承多态的灵活性
如果接口中的行为不是业务内聚的,就需要按照业务进行分组,并将分组后的行为通过单独的接口定义,从而实现不同业务分组的隔离
- 好处
减少冗余行为
稳定性高
可复用性好 - 缺点
接口爆炸
可读性差
高层模块不应依赖低层模块,二者因该依赖于抽象
抽象不应该依赖于细节,细节应该依赖抽象
- 好处
抽象度高
稳定性高
可扩展性好 - 缺点
可读性差
代码测试困难
2、代码规范
代码规范能够使代码具有更好的可读性和可维护性,使团队协作更容易开展
代码规范包含
3、程序命名规范(以Java程序语言为例)
- 工程名称
以项目名称英文单词或首字母缩写组合,首字母大写。如图书管理系统——LibraryManagementSystem或LMS - 包名称
小写单词或缩写,圆点分割,一般3层或以上;从前往后按公司.团队.项目.模块名的方式命名。如aiit.ssl.checkin.login - 类名称
余弦样式:单词组合,首字母大写。如UserDao - 方法或函数名称
正弦样式(驼峰):单词组合,首字母小写。如getUser() - 属性或变量名称
正弦样式(驼峰):单词组合,首字母小写。如userName
4、代码注释规范(以Java语言为例)
JavaDoc
- 代码文件注释
使用块注释,说明文件的主要用途,作者(@author),版本(@version),更新时间(@since) - 类注释
使用块注释,说明类的主要用途,使用示例(@see) - 方法注释
使用块注释,说明方法的主要用途,入参(@param)、出参(@return)及示例(@see) - 语句注释
使用块注释或行注释,说明语句的主要作用

4、程序结构或语句规范(以Java语言为例)
- 分支嵌套不超过3层,多分支使用switch…case
- 循环嵌套不超过2层,优先使用for…each
少用continue和break - 异常处理语句使用try…catch…finally
- 语句对齐与格式化
- 语句按逻辑分层对齐,可以使用tab对齐
- 尽量使用语句格式化
5、文档规范
- 代码文档应说明代码开发语言、开发环境配置方式以及依赖的第三方库
- 代码文档应说明代码运行时环境及对应的具体版本号
- 代码文档应对复杂的业务逻辑进行模型说明,并提供代码行的详细说明
- 代码文档应与最终的软件代码版本保持一致
- 代码文档应对代码可能出现的异常进行说明,并提供解决方案的参考
- 代码文档应说明代码测试的方法,并提供相应的测试例等
6、高质量代码设计方法
- 模块化设计
基本思想:将一个程序按照功能进行拆分,拆分成各个模块,每个模块通过接口调用
划分规则:基于功能划分、基于易变与稳定、基于单一职责 - 面向抽象编程
在模块化设计的基础上,先对每个模块进行抽象处理,定义模块接口,定义各个模块相关联的部分 - 错误与异常处理
- 使用设计模式
二、软件设计模式
1、GRASP模式
- 信息专家
将行为的实现分配给具有该业务处理所需信息的专家类
- 好处
降低代码的耦合
保持类的封装特性 - 缺陷
造成类的肥胖
- 控制器
将事件或请求的分发行为职责分配给控制器类
2、GoF模式
- 创建型模式
单例,原型,构造器,抽象工厂,工厂方法 - 结构型模式
适配器,桥,组合,代理,门面,装饰器,享元等 - 行为型模式
责任链,命令,解释器,迭代器,观察者,访问者等
3、单例设计模式
- 意图:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例的全局访问方法。
- 应用的场景:
某种类型对象实例频繁地创建或销毁,每次创建或销毁消耗大量的程序资源或性能
某种类型对象一旦实例化后,需要持续地向整个系统共享其服务或资源,且保证服务或资源的一致性 - 应用场景的示例:
程序配置类的单例设计
日志服务类的单例设计


- 代码设计中需要注意的问题
- 单例对象实例化的时机
延迟(Lazy)
急切(Eager) - 多线程环境破坏单例特征问题
关键词synchronized - 反序列化破坏单例特征的问题
readResolve()方法 - 类反射机制破坏单例特征问题
枚举,异常检测 - 类克隆方法破坏单例特征问题等
4、适配器设计模式
- 意图:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作
- 应用的场景
当目标对象提供的服务接口与期望的接口不一致时,目标对象和调用者都不允许修改已有的代码
当目标数据源不是调用者所期望的类型,不能通过重新构造数据源和调用者代码的方式解决该问题 - 应用场景的示例
视图适配器
算法适配器


代码设计中需要注意的问题
- 使用类适配还是对象适配
类适配:适配器类继承被适配类
对象适配(更常用):适配器类使用被适配类 - 双向适配技术
调用者和目标对象之间均向对方提供了不兼容的服务,需要借助适配器进行服务转换
5、迭代器设计模式
- 意图:在不暴露内部数据结构的前提下,向外部对象提供遍历聚合元素的统一方法
- 应用的场景
想向外部提供集合数据的遍历方法,但不想暴露具体实现
想为不同的集合结构提供统一的元素遍历接口 - 应用场景的示例
列表数据集的迭代器设计
数据查询结果的迭代器设计

代码设计中需要注意的问题 - 内部迭代器和外部迭代器的区分
内部迭代器指元素的迭代由迭代器自己控制,调用者不能打断迭代过程
外部迭代器指元素的迭代由调用者控制,迭代器只提供迭代接口
大多数迭代器实现使用外部迭代器 - Fail-Fast机制
当在迭代集合的过程中该集合在结构上发生改变的时候,向调用者发出fail-fast事件异常通知 - 谁实现元素迭代算法
迭代器(较为常见)
聚合对象
三、代码评审
1、简介
代码评审(Code Review)是指在软件代码实现后,通过查看和阅读的方式进行代码正确性检查的活动,是软件质量保证的重要方法
- 代码评审是一种静态的代码测试方法,可以发现65%以上的代码bug
- 评审形式
会议 - 评审过程
编写代码->单元测试->评审->优化 - 参与人员
架构师,技术经理,编码人员
2、代码评审内容
- 完整性检查
- 一致性检查
- 正确性检查
- 可修改性检查
- 可预测性检查
- 健壮性检查等
3、代码评审注意事项
- 代码评审参与者至少有一人不是代码的作者
- 源码作者需要对源码进行注释,并且完成了单元测试
- 每次代码评审不超过400行代码量
- 一次代码评审不超过1个小时
- 针对检查目标提前拟定检查列表
- 对检查的结果需要追踪,直至bug完成修复
- 可以借助工具提高评审效率(如git,svn)