软件构造复习 Chapter3

3.1 数据类型与类型检验

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

2. 静态/动态类型检测

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

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

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

3. mutable和immutable

  1. 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

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

4. 常见数据集合类型

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

4.5 迭代Iterator

  1. 在这里插入图片描述一个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 设计规约

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

7. 规约的比较

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

7.3 规约的强度Strong(**)

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

  1. 规约图
    1. 椭圆代表规约,点代表实现
    2. 更强的规约,表达为更小的区域在这里插入图片描述

9. 分析规约

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

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

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

2. 方法的几种类型

  1. Creators 构造器
    在这里插入图片描述
    可能实现为构造函数/静态函数。
    当需要使客户端能调用构造器,又不想让调用者看到creators时可以使用工厂方法
  2. Producers 生产器在这里插入图片描述
  3. Observers 观察器在这里插入图片描述
  4. 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产生/改变对象,看结果是否正确在这里插入图片描述

  1. 不变性
    例如当使用Date类型(mutable)时为了保证不变性,使用提供的对应immutable类java.time.ZonedDateTime在这里插入图片描述return属性值时表示暴露
    且HYPOTENUSE没用private修饰

8. AF与RI

  1. RI:可以映射到用户看到数据集合的条件
  2. AF:用户看到的数据
  3. checkRep()
    在这里插入图片描述

8.4 safety from exposure

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值