一、 Software Construction Process and Configuration Management
1. 传统开发模型
两种基本类型:线性过程、迭代过程
瀑布过程
特点:线性推进、整体推进、非迭代
优点:管理简单
缺点:无法适应需求增加/变化
增量过程
特点:线性推进、增量式(多个瀑布的串行)、非迭代
优点:比较容易适应需求的增加
V-Model
V 模型可以看作瀑布模型的优化,它仍然是线性推进的,瀑布模型存在的问题大多在 V-model 中也存在。
每个开发阶段都有相应的测试对齐进行验证,但是测试与开发是串行而非并行进行的,也就是测试需要等开发完成后再开始。
原型过程
开发出来之后由用户试用/评审,发现问题反馈给开发者,开发者修改原有的实现,继续交给用户评审,循环往复这个过程,直到用户满意为止。重点在于在原型上持续不断地迭代发现用户变化的需求。
特点:迭代推进
优点:开发质量高
缺点:时间代价高
螺旋过程
进行严格的风险分析, 方可进入下一轮迭代
2. 敏捷开发
敏捷开发,即通过快速迭代和小规模的持续改进,以快速适应变化。
敏捷宣言四个维度:
个体和互动高于流程和工具
工作的软件高于详尽的文档
客户合作高于合同谈判
响应变化高于遵循计划
3. 软件配置管理和版本控制
软件配置管理(SCM)
软件配置管理:追踪和控制软件的变化,包括版本控制和软件配置项
软件配置项(SCI):软件中发生变化的基本单元(例如:文件)
版本控制分类
本地版本控制系统
仓库存储于开发者本地机器,无法共享和协作。
集中式版本控制系统
仓库存储于独立的服务器, 支持多开发者之间的协作。
分布式版本控制系统
仓库存储于独立的服务器 + 每个开发者的本地机器。
Git
Git是一个分布式版本控制系统
一个 Git 仓库分为三个部分:
.git 目录:本地的 CMDB
工作目录:本地文件系统
暂存区:.git 目录中的一个文件,隔离工作目录和 Git 仓库
Object Graph
对象图是一个有向无环图,描述了版本之间的演化关系。一条边A→BA→B表示在版本 B 的基础上作出变化,形成了版本 A。
结构
一般:每个 commit 指向一个父亲
分支:多个 commit 可指向同一个父亲
合并:一个 commit 指向两个父亲
一个 “分支”只是一个指向 commit 的别名
HEAD 指向当前工作的 commit
结点
一个 commit 存储一个树形结点。tree 中包含了数个 blob;每个 blob 是一个压缩了的仓库文件,不保存文件名信息。
对于每个文件的每个版本(或是不同文件名但相同内容的文件),Git 只会存储一个 blob,而允许多个 commit tree 指向同一个 blob。
一个 commit 中与之前相比未发生变化的文件,无需重复存储。文件未发生变化,则后续多个版本始终指向同一个 blob;文件发生变化了,存储两份不同的 blob,两个版本指向不同的 blob。
传统 VCS 和 Git 对比
传统 VCS:存储版本之间的变化(行)
Git:存储发生变化的文件(而非代码行), 不变化的文件不重复存储
二、 Data Type and Type Checking
1. 数据类型
Java数据类型:基本类型、对象类型
类型检查
静态类型语言:在编译阶段进行类型检查,所有变量的类型在编译期就已经确定
动态类型语言:在运行阶段进行类型检查,变量的类型在运行期才能确定
静态类型检查:可发现语法错误、类名/函数名错误、参数数目错误、参数类型错误、返回值类型错误
静态类型检查可在编译阶段发现错误,避免了将错误带入到运行阶段,可提高程序正确性/健壮性动态类型检查:可发现非法的参数值、非法的返回值、越界、空指针
静态类型检查是关于“类型”的检查,不考虑值;动态检查是关于“值”的检查。
Java 是一种静态类型语言,它同时具有静态类型检查和动态类型检查。
2. 可变性和不可变性
改变变量和值的区别
改变一个变量:将该变量指向另一个值的存储空间
改变一个变量的值:将该变量当前指向的值的存储空间中写入一个新的值
不变性
不变数据类型(immutable type):一旦被创建,其值不能改变
引用不变:一旦确定其指向的对象,不能再被改变(但其值是可能变化的)
Java 中的 final 关键字
final 变量无法改变其引用(而非值)
不可变类型(immutable)
一旦被创建,就始终代表(对外表现出)同样的值。
可变类型(mutable)
拥有方法可以修改自己的值。
保护可变类型
防御式拷贝:给客户端返回一个全新的对象
大部分时候该拷贝不会被客户端修改, 可能造成大量的内存浪费
单引用局部变量:把对 mutable 对象的引用限制在类/方法内,不对外暴露
如果存在多个引用,使用可变类型就非常不安全
3. 快照图
基本类型
在箭头末端填写值。
对象类型
在箭头末端画一个椭圆,在其中写上对象的类名,更详细的话再包含内部属性。
可变类型对象的椭圆使用单线,而不可变类型的椭圆使用双线。
引用
可变引用使用单线,不可变引用使用双线。
4. 数组和容器
数组是固定长度的序列,而 List 是可变长度的序列。
迭代器
迭代器是一个可变数据类型,它拥有两个方法:mutator 方法 next() 返回容器的下一个数据;observer 方法 hasNext() 返回容器是否还有下一个数据。