#软件构造# Abstraction function and representation invariant(Java抽象数据类型和引用不变量)

    抽象数据型:在数据结构里面是指一个数学模型以及定义在此数学模型上的一组操作,但是在Java里面抽象数据型指的是以abstract定义的函数方法,那么定义这样一个没有函数体的方法有什么作用呢?

    这里我们先引入另外一个概念:接口。

    接口可以说是一个纯粹的抽象类,这里引用一下哈工大王忠杰教授对接口的理解:

接口===CSP认证书、会计师证书、律师证书

类===张三、李四、王五、...、全世界每一个人

张三拥有“CSP证书”,意味着张三具备和实现了CSP证书所要求的全部能力。====类实现接口

张三又拥有了“律师证”,意味着张三既会编程、又会打官司。 ===== 类可以实现多个接口,实现功能组

某企业(i.e., 客户端)需要招募一个会计师,它只需要去找具有会计证书的人即可,无需一个一个人去查每个人的“会计能力”。 (e.g. List a = new ArrayList(); List b = new LinkedList();  a和b都有“会计证”,但是会计能力的实现方式不同)

因为对企业来说,它不在乎某个人是具体怎么实现“会计师”的各项能力,他只在乎这个人有“会计师证”就OK了=======接口与实现的分离

     不难想象:接口是为了某一个方法的重要性而存在,但是接口只允许抽象方法不允许方法实现,这样会导致一些不需要重写的方法多次被重写,导致代码的复用(don’t write it again (DRY)),而abstract类里面则避免了这一情况,但是相对的也造成了一定的风险,视情况选择吧。

      

     引用不变量:这里的不变量指的就是类里面的一些不想被外界修改的值。下面先举一个栗子:

public List getElts() { return elts; }

CharSet s = new CharSet();
s.getElts().add(a);    //假设elts集合是private的,但是通过这样可以对内部内容进行随意修改

     上面这种情况就叫做rep exposure,那么我们有什么办法可以防止这种情况的发生呢?下面举几个栗子

1. 返回不变的元素

Character choose()

{ return elts.elementAt(0); }

Character is immutable.

2. 防御式拷贝(浪费内存)

List getElts()

{ return new ArrayList(elts); // or: return (ArrayList) elts.clone(); }

Mutating a copy doesn’t affect the original.

Don’t forget to make a copy on the way in!

3. 做不可修改的拷贝(不浪费内存)

List getElts()

{ return Collections.unmodifiableList(elts); }

Client cannot mutate Still need to make a copy on the way in

   那么在实战中我们如何检查rep是否泄漏了呢,下面提供一种方法:

   法则:在入口和出口检测是否改变了变量,这样可以有利于我们Debug。

public void delete(Character c) {
    checkRep();
    elts.remove(c)
    checkRep();
}

private void checkRep() {
    for (int i = 0; i < elts.size(); i++) {
    assert elts.indexOf(elts.elementAt(i)) == i;
    }
}

 

你可能感兴趣的:(成长之路,软件构造,Java)