软件构造博客(1)

软件构造知识梳理:

软件构造的质量目标

外部质量因素

  • 正确性
  • 健壮性
  • 可扩展性
  • 可复用性
  • 兼容性
  • 效率
  • 可移植性
  • 易用性
  • 功能
  • 及时性
  • ......

内部质量因素

  • 代码复杂性
  • 可读性
  • 可理解性
  • 整洁
  • 规模

要考虑在不同指标之间折中。

最重要的几个质量因素

  • 正确性、健壮性
  • 可扩展性、可复用性

数据类型与类型检验

Java中的数据类型

基本数据类型

  • int
  • long
  • double
  • char

对象数据类型

  • String
  • BigInteger

按照Java传统,基本数据类型用小写,对象数据类型开头字母大写

基本对象
只有值,没有ID既有ID,也有值
不可变有的可变有的不可变
在栈中分配内存在堆中分配内存(局部变量在栈)
代价低代价高

类型检验

  • 静态类型语言(比如Java)在编译时进行类型检查
  • 动态类型语言,如Python,在运行阶段进行类型检查

静态检查:运行前提示bug

动态检查:运行时提示bug

无检查

静态>动态>无检查

静态检查:关于“类型”的检查,不考虑值

动态检查:关于”值“的检查

可变/不可变

  • 改变一个变量:将该变量指向另一个值得存储空间
  • 改变一个变量的值:将当前变量指向的存储空间写入一个新的值

尽可能避免变化,以避免副作用

不变性

不变数据类型:一旦被创建,其值不能改变

如果是引用类型,也可以是不变的:一旦确定其指向的对象,不能再被改变指向其他对象

用关键字final声明不可变变量

尽量使用 final变量作为方法的输入参数、作为局部变量

Note:

  • final类无法派生子类
  • final变量无法改变值/引用
  • final方法无法被子类重写

可变对象:拥有方法可以修改自己的值/引用

String 是不可变类型

StringBuilder是可变类型

有区别吗?

  • 当只有一个引用指向该值,没有区别
  • 有多个引用的时候,差异就出现了

前者s的值仍为”ab“,后者sb的值变为了”abc“

可变类型的优点

  • 不可变类型频繁修改会产生大量的临时拷贝(需要垃圾回收)
  • 可变类型最少化拷贝以提高效率

使用可变类型可以获得更好的性能,也适合在多个模块之间共享数据

不可变类型的优点

更安全、易于理解、more ready for change

Risk:传递可变对象是一个潜在的错误源泉,一旦被无意中改变很难发现

安全地使用可变类型:局部变量,不会涉及共享;只有一个引用

Array and Collection

  • Array是定长数组
  • List是变长数组

Collections:

  • List
  • Set
  • Map

Iterator

迭代器是一个对象,它遍历一组元素并逐个返回元素

在集合中删除元素时要使用迭代器

Useful immutable types

  • 基本类型及其封装对象类型都是不可变的

  • Java的Collections有提供不可变List、Set、Map的方法

    • Collections.unmodifiableList
    • Collections.unmodifiableSet
    • Collections.unmodifiableMap

    这种包装器得到的结果是不可变的,只能看

设计规约

Function/method in programming language

Specification: Programming for communication

Document

  • 代码中变量的数据类型定义
  • final关键字定义了设计决策

代码中的设计决策:面向编译器

注释形式的“设计决策”:面向用户和程序员

Specification and Contract

  • Spec给供需双方都确定了责任,在调用的时候双方都要遵守
  • 区分责任
  • 客户端无需阅读调用函数的代码,只需理解spec即可

Behavioral equivalence (行为等价性)

两个函数是否可以相互替换

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

Spec的结构:前置条件和后置条件

  • 前置条件:对客户端的约束,在使用方法时必须满足的条件
  • 后置条件:对开发者的约束,方法结束时必须满足的条件
  • 契约:如果前置条件满足了,后置条件必须满足

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

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

Designing specifications

规约的分类

规约的强度:

S2>S1意味着:

  • S2的前置条件更弱
  • S2的后置条件更强

就可以用S2替代S1

越强的规约意味着实现者的责任越重,而客户端的责任越轻

  • 确定的规约:给第一个满足前置条件的输入,其输出是唯一的、明确的
  • 欠定的规约:同一个输入可以有多个输出
  • 非确定的规约:同一个输入,多次执行时得到的输出可能不同

操作式规约,例如伪代码

声明式规约:没有内部实现的描述,只有“初-终”状态

声明式规约更有价值

规约的图示

某个具体实现, 若满足规约,则落在其范围内;否则,在其之外

程序员可以在 规约的范围内自由选择实现方式

客户端无需 了解具体使用了哪个实现

更强的规约,表达为更小的区域

设计好的规约

  • Spec描述的功能应该单一、简单、易理解

  • 不能让客户端产生理解的歧义

  • 足够强(让client放心)

  • 足够弱(减轻开发者负担)

  • 使用抽象类型

  • precondition or postcondition?

    客户端不喜欢太强的precondition,惯用做法是不限定太强的precondition,而是在postcondition中抛出异常:输入不合法

    归纳:是否使用前置条件取决于:

    • check的代价
    • 方法的使用范围

    如果只在类内部使用该方法(private),那么可以不用前置条件,在使用该方法的各个位置进行check--责任交给内部client

    如果在其他地方使用该方法(public),那么必须使用前置条件,若client端不满足则方法抛出异常。

抽象数据类型

  • creator:从无到有,产生一个新的对象
  • producer:从旧到新,从旧对象产生新对象
  • observer:观察器
  • mutator:变值器,改变对象属性,通常返回void,也可能返回非空类型

AF、RI、rep exposure

表示值空间:R,实现者看到和使用的值

抽象值空间:A,client看到和使用的值

R->A:

  • 满射
  • 未必单射
  • 未必双射

AF,RI,safe from rep exposure的docs

  • ADT的规约里只能用client可见的内容(A中的值)来撰写,包括参数、返回值、异常等
  • 规约里不应谈及任何内部表示(以及R中的值)

用ADT不变量取代复杂的Precondition。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值