软件构造复习 Chapter3

    技术2026-08-10  14

    文章目录

    3.1 数据类型与类型检验2. 静态/动态类型检测3. mutable和immutable3.4 把mutable转化成immutable 4. 常见数据集合类型4.5 迭代Iterator 5. useful immutable types 3.2 设计规约7. 规约的比较7.3 规约的强度Strong(**) 9. 分析规约 3.3 抽象数据类型(ADT)***2. 方法的几种类型3. 常见分类6. 测试ADT8. AF与RI8.4 safety from exposure

    3.1 数据类型与类型检验

    基本数据类型对象数据类型存在栈里存在堆里只有值,没有ID(与其他值无法区分)既有ID,也有值Immutablemutable

    2. 静态/动态类型检测

    考试可能重点:1. 画图 2. 转化为immutable

    静态类型检测:赋的值是否在变量类型范围内 动态类型检测:运行的时候针对某个值检测(注:JAVA是静态类型检测,运行时不会做类型检测) 动态>>静态>>无检查

    静态类型检测动态类型检测编译阶段检查运行阶段检查 静态类型检测 语法错误 类名/函数名错误 参数数目错误 参数类型错误 返回值类型错误动态类型检测 非法的参数值 非法的返回值 越界 空指针

    3. mutable和immutable

    immutable 改变值的时候要申请一个新的存储空间,然后使变量指向新的存储空间 注: 1) 不包含任何可以改变属性值的方法(eg:setter) 2)属性中无public 3) 不能直接return属性值,而是要return一个copy 2. mutable:值可以被改变 危险(多个引用共享数据),但同时可以提高效率,不用产生大量需要回收的无用变量 当返回groundhogAnswer时返回的相当于是它的引用,相当于groundhogAnswer和partyDate现在指向的是同一个内存区域 3. final 1. final类无法派生子类 2. final变量无法改变值/引用 3. final方法不能被子类重写

    3.4 把mutable转化成immutable

    防御式拷贝defensive copy 例如:把return groundhogAnswer;改为return new Date(groundhogAnswer.getTime()); 缺点是:可能造成大量的内存浪费 改为: 从而在下图应用中不会因为end.setYear(78)改变p的值 snapshot diagram 基本类型值/对象类型值 基本类型不会把引用存在堆里(不会存变量名) 对象的属性(如x,y)和对象一起放在堆里 对象的引用放在堆里immutable/mutable/final immutable对象:双线椭圆 mutable: final:不可变的引用(双线) 注:引用不可变,但指向的值可以变(是mutable时可以改变值)

    4. 常见数据集合类型

    Array a[2] a[2]=0 a.lengthList List中的每个成员都是对象 list.get(2) list.set(2,0) list.size()Set 没有重复元素 s1.contains(e) s1.containsAll(s2) s1.removeAll(s2)Map map.put(key,val) map.get(key) map.containsKey(key) map.remove(key)

    4.5 迭代Iterator

    一个iterator的类的内部实现 public class MyIterator { private final ArrayList<String> list; private int index; /** * Make an iterator * @param list list to iterate over */ public MyIterator(ArrayList<String> list) { this.list = list; this.index = 0; } /** * Test whether the iterator has more elements to return * @return true if next() will return another element * false if all elements have been returned */ public boolean hasNext(){ return index < list.size(); } /** * Get the next element of the list * Requires: hasNext() returns true * modifies: * @return next element of the list */ public String next(){ final String element = list.get(index); ++index; //改变了index的值,故该类是mutable的 return element; } }

    画出来的snapshot图: 2. remove时用iterator的remove取代list的remove 改为:

    5. useful immutable types

    mutable: Date,List,Set,Map immutable: 通过以下方法使mutable变为不可变(编译阶段无法静态检查) Collections.unmodifiableList Collections.unmodifiableSet Collections.unmodifiableMap

    3.2 设计规约

    参数类型、返回值类型是否匹配,在静态类型检查阶段完成规约的作用: 规约可以隔离“变化”规约可以提高代码效率,实现者不用写代码保证输入的正确性规约扮演“防火墙”的角色 规约内容 输入/输出的数据类型功能和正确性性能 性质 行为等价性—— 站在客户端视角规约结构 前置条件 requires——客户端约束(java:@param)后置条件 effects——开发者约束(java:@return)异常处理 前置条件违反的情况(java:@throws) 注:没写异常处理时,只要违反了前置条件,那么得到任何结果都是正确的 依据规约的黑盒测试 根据规约设计测试用例,不考虑实现,同其他client一样 不能在test时猜测实现find的内部方法

    7. 规约的比较

    规约的确定性 确定的规约:给定precondition输入,输出是唯一的、明确的规约的陈述性 操作式规约:eg:伪代码 *声明式规约:没有内部实现的描述,只有“始、终”

    7.3 规约的强度Strong(**)

    规约强度S2>=S1:S2前置条件更弱,或(保证S1的前置条件的基础上)后置条件更强 此时可以用S2替换S1 无法比较的情况:越强的规约,更少的实现可以满足,更多的client可以调用

    规约图 椭圆代表规约,点代表实现更强的规约,表达为更小的区域

    9. 分析规约

    内聚的 Spec描述的功能应该单一、简单、容易理解 最好不要把两个功能放在一个方法实现 反例:信息丰富的 return不要出现二义性规约应该足够强壮Strong 开发者应该考虑各种特殊情况并在post-condition给出处理措施规约也不能太强 太强的spec很多时候难以达到,给开发者增大难度 反例:规约里使用抽象类型 例如尽量使用List、Set而非ArrayList、HashSet,会给方法实现和客户端更大的自由度前置条件还是后置条件? 1. 不写precondition代价很大时,在规约里加入precondition可以把责任给client 2. 方法使用范围只在类的内部时,可以不用precondition 惯用做法:precondition不太强,而是在postcondition中抛出异常:输入不合法

    3.3 抽象数据类型(ADT)***

    ADT的特性:表示泄露、抽象函数AF。表示不变量RI

    2. 方法的几种类型

    Creators 构造器 可能实现为构造函数/静态函数。 当需要使客户端能调用构造器,又不想让调用者看到creators时可以使用工厂方法Producers 生产器Observers 观察器Mutators 变值器——直接改变对象属性的值(只存在于mutable类中)通常返回void,但也可以返回值非空

    3. 常见分类

    4. 设计抽象数据型 1. 操作简洁、一致 2. 操作要足够多 getter、setter、或提供size操作就不用每次都遍历得出list的size了 5. 表示独立性 client使用ADT时无需考虑其内部如何实现,ADT内部表示的变化不影响外部Spec和客户端**(把所有属性设为private)** 不直接访问属性,通过get方法访问

    6. 测试ADT

    测试creators、producers、mutators时:调用observers来观察这些方法的结果是否满足规约 测试observers:调用creators、producers、mutators产生/改变对象,看结果是否正确

    不变性 例如当使用Date类型(mutable)时为了保证不变性,使用提供的对应immutable类java.time.ZonedDateTimereturn属性值时表示暴露 且HYPOTENUSE没用private修饰

    8. AF与RI

    RI:可以映射到用户看到数据集合的条件AF:用户看到的数据checkRep()

    8.4 safety from exposure

    反例: (Set和Map都是mutable类型的) 可以两种方式修改以防止表示暴露: 1. getFollowers时返回defensive copy 2. getFollowers时返回immutable类型的Set

    Processed: 0.011, SQL: 9