简要介绍:
RI是表示不变量,如果谁破坏了不变量则引起异常,因此有了RI我们可以更容易地捕捉到由于数据结构破坏而引起的bug。
转换为数学问题,AF(s): R→A,R为内部表示是具体的,A为现实世界的抽象空间,是抽象的。
s的定义域可以理解为RI,不满足RI的元素没有映射到abstract space的像,即RI(s)=false。
RI的保持可以理解为一种条件的判断成立,如a>0…
在写代码的时候,将AF和RI写在rep附近,例:
public class CharSet {
private String s;
// Rep invariant:
// s contains no repeated characters
// Abstraction function:
// AF(s) = {s[i] | 0 <= i < s.length()}
...
}
checkRep
对rep时刻满足RI的检查——private void checkRep()
除了Observer,其他Creator、Producer、Mutator都要在函数结束前调用checkRep函数,因为这些操作都伸入了rep,但在观察者中调用也是锦上添花,所以在一个类的所有操作中都调用一遍checkRep是极好的。
checkRep的编写需要根据RI,更细节的是关于Java的硬条件,即No null values in the rep。这是公认且默认的条件,一般在RI中不用单独强调,但是在编写checkRep函数时要注意到这一点,举个例子
class CharSet {
//rep
String s;
//Rep invarient:
// s.length() is even.
}
//Check that the rep invarient is true
private void checkRep() {
assert s.length() % 2 == 0;
...
}
这样的checkRep就不用单独写assert s.length() != null
因为调用s.length()的时候就会自动检查s非空,如果s没有被检查,那么需要明确地调用assert s≠null进行检查。
When you describe the rep invariant and abstraction function, you must be precise:
- It is not enough for the RI to be a generic statement like “all fields are valid.” The job of the rep invariant is to explain precisely what makes the field values valid or not.
- It is not enough for the AF to offer a generic explanation like “represents a set of characters.” The job of the abstraction function is to define precisely how the concrete field values are interpreted. As a function, if we take the documented AF and substitute in actual (legal) field values, we should obtain out a complete description of the single abstract value they represent.
// Immutable type representing a tweet.
public class Tweet {
private final String author;
private final String text;
private final Date timestamp;
// Rep invariant:
// author is a Twitter username (a nonempty string of letters, digits, underscores)
// text.length <= 140
// Abstraction function:
// AF(author, text, timestamp) = a tweet posted by author, with content text,
// at time timestamp
// Safety from rep exposure:
// All fields are private;
// author and text are Strings, so are guaranteed immutable;
// timestamp is a mutable Date, so Tweet() constructor and getTimestamp()
// make defensive copies to avoid sharing the rep's Date object with clients.
// Operations (specs and method bodies omitted to save space)
public Tweet(String author, String text, Date timestamp) { ... }
public String getAuthor() { ... }
public String getText() { ... }
public Date getTimestamp() { ... }
}