ADT中的RI,AF,Rep Exposure

RI

RI(Representation invariant):表示不变量,即类中属性必须满足的那些条件。

eg1:

构建一个Person类的时候,我们并不希望一个人的名字为null,或者他的年龄为负数,所以我们可以写下对应的RI:

public class Person{

    private String name;
    private Integer age;

    /*
      RI:
        name != null
        age >= 0
    */
}

eg2:

Lab2中Edge类的实现(有向图的一条有向边),在spec中要求了每条边的起点和终点必须是非空的,并且这条边的权重必须为正。所以可以写下对应的RI:

class Edge<L>{

    private final L source;
    private final L target;
    private final int weight;

    /*
       RI:
         source != null;
         target != null;
         weight > 0;
    */
}

RI小结:

①为什么要写RI:

一个类中有许多属性,他们必须满足一些特定的条件以防止程序运行时出现一些错误。写下RI可以告知这个类的使用者需要注意哪些地方,还可以根据RI编写checkRep函数来检查这些不变量。

②RI限定了类属性的取值:

例如Person类中name可以是任意的字符串(包括空串),但是我们不希望name为空,所以人为限定了 name != null。 这时,name的取值集合就不再是任意字符串,而变成了除了空串以外的字符串,这个集合显然是所有字符串集合的一个子集。(设所有字符串的集合为U,满足RI的name的取值集合为A,那么显然 A \subset U

③:RI就是一个条件:

这个条件是开发人员自己确定的,它与这个抽象类的使用场景有关。这个条件一旦确定就不能再改变(毕竟它的名字叫表示不变量)。这个条件是“对各个类属性的合法取值的一种描述”。符合RI描述的取值为合法的,否则是不合法的。

checkRep()

这是一个用来检查表示不变量(RI)的函数。一般使用断言来检查,这样在程序正式发布的时候,可以控制JVM中的开关来选择是否执行这些断言。

eg1:

public class Person{

    private String name;
    private Integer age;

    /*
      RI:
        name != null
        age >= 0
    */

    private void checkRep(){
        assert name != null;
        assert age >= 0;    
    }
}

eg2:

class Edge<L>{

    private final L source;
    private final L target;
    private final int weight;

    /*
       RI:
         source != null;
         target != null;
         weight > 0;
    */
    
    private void checkRep(){
        assert source != null;
        assert target != null;
        assert weight > 0;
    }
}

由上面两个例子可以看到,checkRep()就是按照RI的内容来写的。在creator,producer,mutator这些类型的方法中调用checkRep方法来检查RI是否还保持不变,如果断言没通过则是发生了错误。

AF

AF(Abstraction function):抽象函数,类似于一个映射。

说明:集合A为抽象空间(Abstract) ,集合R为表示空间(Rep)。

集合A是抽象值构成的空间:即client看到和使用的值。

集合R是表示值构成的空间:即实现者看到和使用的值。

用户(client)只关注抽象空间A,而ADT的实现者需要关注两个空间。(用户只用知道怎么用即可,具体内部怎么实现不需要关心。而ADT实现者必须对两个空间有清晰的把握)

如上图所示,这就是 “构造的程序的 ADT内部的量” ——> “客户想要操作的量”  这样一个映射。

AF一定是满射,不一定是单射,因此不一定是双射。

也就是R中的对象不一定能找到A,但是A中的抽象必须有R中对应的对象。(类比:客户要求的功能你必须要实现,但是你另外多写了什么没有关系)

这里引用老师ppt的一段内容:

What determine AF and RI?

 

 

 

eg:

这个ADT是要表示一条推文:

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 <= 280
        
        Abstraction Function:
            AF(author,text,timestamp)=a tweet posted by author,with content text,
                                      at time timestamp
    */
    
}

Rep Exposure

Rep Exposure:表示泄露。

java中数据类型可以分为mutableimmutable两种。对前者进行的操作会直接改变其内部数据,而对后者的操作不是改变其内部值,而是构造新的对象。因此,对于mutable的数据,如果没有良好的保护,意味着client对其的调用可以直接修改内部数据。

mutable类中可以直接用setter对其相应的内部值进行修改,而且这种修改是对类中变量指向的地址的内容进行修改,这就会导致表示泄露。应对此情况的方法是,getter得到的不应该是类中的变量,而是类中变量的一个副本,这也就是常说的防御式拷贝。

防止表示泄露通常有以下几种方法:

1. 使用privatefinal关键字修饰:------即将类中所有的属性(变量)定义为private类型,目的是不让用户得到你的内部属性。final使属性不能被修改和继承。
2. 尽量使用immutable数据类型,比如能使用String就不使用StringBuilder,能使用Instance或
LocalDateTime就不使用Data

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值