软件构造复习笔记(三)

Specification、前置/后置条件:

方法的规约:

 

 

前置条件(requires):对客户端的约束,在使用方法时必须满足的条件。

后置条件(effects):对开发者的约束,方法结束时必须满足的条件。

如果前置条件满足,则后置条件一定要满足。如果前置条件不满足,可以做任意事。

静态类型声明是一种规约,可以根据此进行静态检查。

方法前的注释也是一种规约,但是需要人工判定是否满足。

前置条件看@param,后置条件则观察@return和@throws。

一个规约,应该关于参数和返回的值,但是不应该关于局部变量和私有区域。

可变/不可变方法的规约:一定要体现出这个方法是否可变:

 

 

除非后置条件中声明过,否则方法内部不应该改变输入参数。

行为等价性:

两个函数对用户来说是否等价。客户端视角看行为等价性。

根据规约判断是否行为等价。

 

单纯看实现代码,并不足以判定不同,implementation是否行为等价,必须结合spec判定行为等价性。

规约的强度:

如何判断哪个规约更好:规约的确定性,规约的陈述性,规约的强度

如何比较两个规约,以判断是否可以用一个规约替换另一个。

spec变强:更放松的前置条件+更严格的后置条件

 

再判定后置条件是否更强的时候,我们需要限定较强的前置条件下观察两个规约的后置条件:

 

 

 ADT 操作的四种类型:

ADT:强调作用于数据上的操作,程序员和client无需关心数据如何存储,只需要设计/使用操作即可。

构造器:新创建一个对象

生产器:在已有的对象上创建一个对象

观察器:look look

变值器:only mutable

 

构造器:可能是构造函数,像new ArrayList();或者仅仅是一个静态函数,如Arrays.asList();

一个静态的构造器可以被称为工厂方法

String.valueOf(Object Obj)就是一个工厂方法

变值器:通常返回void,也有可能返回非空类型如Set.add()返回一个Boolean。

表示独立性(Representation Independence) 表示泄露

表示独立性:用户在使用ADT时不需要考虑内部如何实现,ADT内部表示的变化应该影响外部的规约和客户端。

表示泄露:ADT中的数据被外界获取。

ADT测试:

测试creators,producers,and mutators:调用observers来观察这些operations的结果是否满足spec;

测试observers:调用creators,producers,and mutators等方法产生或改变对象,来看结果是否正确。

不变量、表示不变量 RI:

保持不变量:immutable就是一个典型的不变量

由ADT来负责不变量,与client端的任何行为无关。

Private可以让变量域和方法只有再一个类中被访问。

Final可以保证变量域不发生改变。

除非迫不得已,否则不要把希望寄托于客户端上,ADT有 责任保证 自己的invariants,并避免“表示泄露”。

用immutable类型彻底避免表示泄露。

表示空间、抽象空间、AF:

R:表示空间

A:抽象空间

ADT开发者关注表示空间R,clien关注抽象空间A

一定是满射,但未必是单射

AF:R->A

RI:R->Boolean

表示不变性RI:某个具体的“表示”是否合法

 

在所有可能改变rep的方法内都要检查(creators,producers,mutators)

利用checkRep()。

有益的可变性:改变R值,但是一定不可以改变A值!!!

这 种 mutation 只是改变了R值,并未改变 A 值,对 client来说是immutable 的->“ AF 并非单射”,从一个R值变成了另一个R值。

以注释的形式撰写 AF、RI:

在代码中用注释形式记录AF和RI

要精确记录RI:rep中的所有fields何为有效

要精确记录AF:如何解释每一个R值

 rep exposure safety argument表示泄漏的安全声明:给出理由来证明代码并未对外泄露其内部表示。

 

ADT的规约只能使用client可见的内容来撰写,包括参数、返回值、异常等。

如果规约里需要提及“值”,只能使用A空间中的值。

接口、抽象类、具体类:
实例方法和类方法的区别:类方法前有static。

 Interface和Class: 定义和实现ADT

接口之间可以继承与扩展

一个类可以实现多个接口(从而具备了多个接口中的方法)

一个接口可以有多种实现类

Default方法:接口中每个方法都要在所有类中实现,用default可以统一实现某些功能而无需在各个类中重复实现它。

接口中不应该存在构造器,但是可以有工厂方法代替构造器:

 

 

抽象类:

一个类至少有一个抽象方法(没有实现的方法)

如果某些操作是所有子类型都共有,但彼此有差别,可以在父类型中设计抽象方法,在各子类型中重写。

所有子类型完全相同的操作,放在父类型中实现,子类型中无需重写。有些子类型有而其他子类型无的操作,不要在父类型中定义和实现,而应在特定子类型中实现。

继承,overriding

如果一个方法不能被重写,要加上final。

子类只能添加新方法,不能重写超出类中的方法

重写的函数:完全相同的signature

实际执行调用哪个方法运行时决定

重写之后可以利用super()复用父类型中函数的功能,并对其进行了扩展

 

 

多态、子类型、重载:

特殊多态:功能重载

参数化多态:

子类型多态

重载:多个方法具有同样的名字,但有不同的参数列表或返回值类型

价值:方便 client 调用, client 可用不同的参数列表,调用同样的函数

方法重载是静态多态。

必须是不同的参数列表,其他可以相同也可以不同。

注意参数列表中,参数名称是可以不同的,但是参数类型相同也算相同。

重写类型的方法在运行是确定数据类型,但是重载类型的方法在编译时就确定了数据类型。

 

泛型:

用<>来声明变量类型的时候可以采用泛型。

 

  1. 泛型的接口,非泛型的实现类

  1. 泛型接口,泛型的实现类

通配符:只能在使用泛型时出现

 

运行时泛型擦除

子类型的规约不能弱化超类型的规约

子类型多态:不同类型的对象可以统一的处理而无需区分

instanceof():判断类型是否相同,相同返回true

重写toString:

我们需要让toString的输出满足格式:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值