HIT软件构造 blog5


前言

进入最后的复习季了,在这里简单记录一下我的复习过程和总结吧,记录一下错题然后复习一下最近学的设计模式


一、错题思考与分析

1.1 Profiling 的考察

以下关于软件构造过程各阶段的说法,不正确的有____

A Profiling是static code analysis的一种典型形式
B Code review的目的是发现代码中的潜在错误
C Refactoring是在不改变代码功能的前提下重写代码,以消除bug,提高质量
D Build是将软件从开发态转化为可运行状态的过程

正确答案:A

注:
profiling 是指在程序执行过程中,收集能够反映程序执行状态的数据。
这里所收集的数据我们称之为程序的 profile。

1.2 程序的构造次序

以下说法,不正确的是___

A 常规的构造次序是:coding ->refactoring-> testing -> code review-> debugging ->build ->dynamic profiling
B 通过code review和profiling找出可能的bug,通过testing找出真实的bug,通过debug找出bug的根源
C 利用spec构造完备的测试用例,后续对代码的任何修改,都应重新运行测试用例
D Build脚本是由配置语言书写,告知build工具如何一步一步完成自动化build任务

正确答案:A

正常顺序如下:
(1) Programming:有编程语言,也有建模语言,如UML,还有配置语言,如XML、JSON。

(2) Code review、Static code analysis:可以使用工具来发现bug,如CheckStyle, SpotBugs。

(3) Testing:测试,单元测试、集成测试、系统测试…

(4) Debugging:调试

(5) Dynamic code analysis/profiling:在程序运行的过程中查看并发现问题,本课程不涉及这部分

(6) Refactoring:重构不改变功能,只是处于更容易维护的目的对代码优化

(7) Build:第2部分

1.3 git的object graph

针对Git仓库的object graph,以下不正确的说法是__

A 它是一个有向图,边的方向指向产生时间较晚的commit节点
B 一个commit节点可以有0个、1个、2个、多个parent节点
C 一个branch(分支)本质上相对于一个指向特定commit节点的“指针”
D 可以有两个不同的branch指向同一个commit节点
E git commit指令相当于在object graph当前分支HEAD指向的commit基础上,派生出一个新的commit节点。

正确答案:AB

注:A选项的object graph确实是有向图,但是应该是指向产生时间较早的节点
B选项,parent节点只能0、1、2个

object graph知识点的补充:

  • 指版本之间的演化关系图,一条边A->B表征了**“在版本B的基础上做变化,形成了版本A”**
  • commit是对象图中的节点,多个commit之间的关系一般来说由三种:
    1.每个commit指向一个父亲
    2.多个commit指向同一个父亲:分支
    3,一个commit指向两个父亲:合并
    一个branch是一个指向一个commit的名字
    HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
    在这里插入图片描述

1.4 对于方法参数的保持

程序员应该有一个共识,方法的参数应该保持不变,尤其是你的方法的参数是mutable类型的时候
例子:
方法参数为mutable类型
在这个方法中,方法内部通过set将mutable的参数LIst进行了修改,不符合规范,导致下面出现错误:
错误·出现

1.5 Date和 LocalDateTime

Date是可变类型,LocalDateTime是不可变类型

1.6 防御式拷贝

(1)类中的构造器赋值时使用防御使拷贝
在构造器中使用
(2)类中的返回值时使用防御使拷贝
在返回值中使用

1.7 Snapshot Diagram

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
例子:
例子

1.8 老师强调的几个一定要记住的Snapshot Diagram

List:
在这里插入图片描述
set:
在这里插入图片描述
map:
在这里插入图片描述

1.9 迭代器

Iterator: Iterator是一个可变的类,index是可以修改的,注意list的箭头是双箭头,用final修饰
而且**在迭代器中不要使用remove操作!**因为删除后会继续向前补齐,会出现删除错误!
在这里插入图片描述
如果用隐式迭代呢?不可以的,因为这样在遍历subjects的同时也在修改subjects,所以不可以
在这里插入图片描述
正确方法:使用iterator的remove方法
在这里插入图片描述

1.10 数据类型与类型检验

在这里插入图片描述
答案:ABD
A选项可以泛泛地理解为对的,JAVA虚拟机很复杂,局部变量在stack
B选项AVA虚拟机会把int里面常用的等一些东西放在一个缓存中,而对象在堆中,int会快

二、知识点复习

2.1 行为等价性

行为等价性应该站在客户端视角看,如果这两个方法在任何情况下提供的行为都是一样的,那么说明是行为等价性。判断等价应该在指定的条件下
例如:
在val不存在时,在客户端角度,这两个方法是不等价的;
出现很多次时候,也不等价;这两种情况时候的返回值是不一样的
在这里插入图片描述

2.2 规约

前置条件:对客户端的约束,使用时候必须满足的条件 ——>requires
后置条件:对开发者的约束,方法结束时候必须满足的条件 ——>effects

关系:
前置条件满足,后置条件必须满足
前置条件不满足,则方法可做任何事情

2.3 三个关键字

前置条件 描述参数:@param (参数是什么,代表什么含义,应该满足什么条件)
后置条件 :如果输入符合如何返回:@return
如果异常情况:@throws

例子(找错误):
错误例子

  1. 第一行少一个星号!
  2. 不应该有requires和effects,没有这两个关键字
  3. param和return无需将String和boolean写出来,这两个在函数名中已经显现

2.4 比较规约

更强的规约和更弱的规约?
假设规约的强度是S2>=S1

  1. S2的前置条件更弱
  2. S2在满足S1的前置条件的条件下, S2的后置条件要更强

即:spec变强,是更放松的前置条件+更严格的后置条件
更强的规约可以替代更弱的规约

对于第二条的“S2在满足S1的前置条件的条件下”,我没可以举例子如下:
在这里插入图片描述
在相同的S1的前置条件下,S2的effects与S1是一样的,因为每个val必被找到

PS:图的面积越小,spec越强
在这里插入图片描述

2.5 设计规约的几个原则

  1. spec描述的功能应单一、简单、易理解(如果该规约做了两件事情,要分离成两个方法)
  2. 规约不能有歧义的
    例子:
    用户端返回空值的时候,可能是val为空值,也可能是key不存在
    在这里插入图片描述
  3. 既要足够强,也要足够弱
  4. 规约应该用抽象数据类型,比如List而不是ArrayList,因为如果用ArrayList无形给客户更多的要求,用抽象数据型可以给客户端更大的自由度
    在这里插入图片描述

2.6 设计规约的几个最后练习

在这里插入图片描述
答案:ABCE
解析:尤其是B选项,对于有行为等价性的两个方法来说,功能一定是一样的,他们可能展现出不同的性能

2.7 ADT的四类方法!!!(十分重要)

1. Creators 构造器 和类的名称应该一样,两种实现:采用静态方法实现对象的构造,采用new来构造
2. Producers 生产器: 由老的对象返回一个新对象,比如一个String的concat
3. Observers观察器: 观察老的对象返回观察的结果
4. Mutators 变值器: 改变属性的值,返回通常是void,不过也可以返回boolean查看是否失败
返回void一定变值器,但是变值器有可能返回void

在这里插入图片描述
在这里插入图片描述
PS:creator的返回值:
实际上,类的构造器有返回值,返回的是该类的实例,因此类的构造器返回值类型是当前类,因此无需定义返回值类型。但注意:不能在构造器里显示使用return来返回当前类的对象,因为构造器的返回值是隐式的。只写return;不会报错。”

2.7 ADT的四类方法举例

  1. Integer.valueof() creator(构造一个Integer的对象)
  2. BigInteger,mod() producer
  3. List.addAll() mutator
  4. String.toUpperCase() producer
  5. Set.contains() observer
  6. Map.keySet() observer !!!而不是producer,返回的是一部分
  7. Collections.unmodifiableList() producer
  8. BufferedReader.readLine() mutator而不是creator/producer是因为他不会实例化缓冲区或者返回一个新的
    缓冲区对象,他是修改第一行来使每次的返回值不一样,实质上是mutator
  9. substring(int start int end) producer 返回值也是String

2.8 ADT的第一个特性:表示独立性(RI)

写代码的顺序:Sepecification -> Representation -> Implementation
表示独立性,client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不应影响外部spec和客户端。但是平常说的RI应该是表示不变量:Rep Invariant
PPT中违反RI的例子:
违反RI
因为在这里的属性用的public,所以用户端调用可能会通过直接调用属性,但是内部的属性如果改变名字或者实现方式,那么客户端那里的调用就直接失效。改变方法:
(PPT这里的属性应该是private)提供一个返回list的方法让客户端调用即可
在这里插入图片描述
如果属性用的public而不是private会出现表示泄露,即:representation exposure:不仅影响不变性,也影响表示独立性,无法在不影响客户端的情况下改变其内部表示

2.9 ADT 测试

如何测试observers,如何测试其他三种
在这里插入图片描述

2.10 两个表示空间的关系

三个特点:满射,未必单射,未必双射(有不满足RI的值)
在这里插入图片描述

2.11 AF与RI的注意事项

一定注意AF和RI是给程序员看的,而不能写在spec中
客户端可以看到的:
A空间、方法(Creator、Producer、Observer、Mutator)
开发人员:
A空间、R空间、方法、Rep、RI、AF

PPT上的一点小坑分析:
在下面的PPT中,右下角的方法的spec要求将字符集合中的c都删掉,我们挨个分析每个rep:

  1. 字母严格大于,说明没有一样的字符,删除一个以后仍然满足
  2. 长度是偶数,删除一个以后明显不符合要求
  3. 不会出现超过一次,那么直接删除以后也符合RI
  4. 如果被删除的字符集合是xyyx,那么由于indexof的返回值应该是第一个c的位置,那么得到的是yyx,没有按照spec把x全部都删除
    在这里插入图片描述

2.12 checkRep 随时检查RI

需要注意的是:

  1. Observer可以不用进行checkRep
  2. 在开发阶段可以checkRep,如果对性能影响较大,在交付阶段,可以将checkRep注释掉

到底要在什么方法中checkRep呢?
creator和producer 两个方法都要返回一个对象,所以需要进行checkRep
mutator 因为做了改变所以要check
observer 以防它在途中误操作进行了修改

2.13 有益的mutation (Immutable 类的mutation)

这里说明Immutable 类是可以有的mutation的

2.14 避免表示泄露

  1. 属性
    确保所有的变量都是private
    如果用了public那么一定有表示泄露!!!!!改不改不一定,但是一定泄露了。
    变量是否加final与表示泄露没有关系
    确定可变类型的属性

  2. 方法上
    构造函数传递可变类型的类——拷贝
    返回值为可变类型的get函数——拷贝

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值