浅谈ADT和OOP

ADT和OOP

ADT(Abstract Data Type) 抽象数据类型

OOP(Object-Oriented Programming) 面向对象的程序设计

数据类型

基本数据类型 对象数据类型
在这里插入图片描述

基本数据类型的声明方式:

int a = 0;
对象数据类型的声明方式:

List = new ArrayList<>();
将基本类型包装为对象类型:Integer,Double,Boolean,Long,Character,Float等,通常在定义集合类型的时候使用,除此之外一般要避免使用这些类型。

类型检查

静态类型检查:在编写代码时进行检查。能检查的错误有语法错误、类名/函数名错误、参数数目错误、参数类型错误、返回值类型错误等。是关于“类型”的检查。

动态类型检查:在代码运行时进行检查。能检查的错误有非法参数值、非法返回值、越界、空指针等。是关于“值”的检查。

无检查:从不检查。

可变和不可变

改变一个变量:将该变量指向另一个值的存储空间。

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

不变对象:一旦被创建,始终指向同一个值/引用。

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

例如,String是不可变的,将"a"变成"ab",实际上是创建一个新的内容为"ab"的String;而StringBuilder是可变的,将"a"变成"ab",则是直接改变其值。

两者各有优缺点,使用可变类型,可获得更好的性能,但安全性欠佳;不可变类型在修改时会产生大量垃圾,可它更加安全。

Sanpshot Diagram 规则

1.基本类型的值

在这里插入图片描述

2.对象类型的值
在这里插入图片描述

List

在这里插入图片描述

Set

在这里插入图片描述

Map

在这里插入图片描述

3.可变类型用单椭圆,不可变类型用双椭圆

在这里插入图片描述
在这里插入图片描述

4.可变引用(可以指向不可变的值)用单线箭头,不可变引用(可以指向可变的值)用双线箭头

在这里插入图片描述

使用snapshot diagram,可以帮助我们更好地理解变量改变的过程,分析代码中出现的错误。

规约(Specification)

规约起到防火墙的作用,只讲这个代码能做什么,而不涉及具体的实现方法,精确的规约有助于区分责任。

前置条件:对客户端的约束,使用这个方法时需要满足的条件。

后置条件:对开发者的约束,方法结束时需要满足的条件。

如果前置条件满足了,后置条件必须满足;如果前置条件不满足,则后置条件不一定会满足。

更强的spec指更弱的前置条件和更强的后置条件。

行为等价性:两个方法实现的过程不同,但它们遵循的规约相同,则说这两个方法是行为等价的。

spec具体写法如下:

/**
 * 这里写这个方法的功能。
 * @param attr1 参数attr1需要满足的条件
 * @param attr2 参数attr2需要满足的条件
 * ……
 * @return ret 返回值满足的条件
 */
 ReturnType method(AttrType1 attr1, AttrType2 attr2, ……) {......} 

ADT

ADT是由操作定义的,与其内部如何实现无关。

可变类型的对象提供了可改变其内部数据的操作。不变数据类型的操作不改变其内部值,而是构造新的对象。

ADT操作的四种类型:Creator(构造器)、Producer(生产器)、Observer(观察器)、Mutator(变值器)

Creator(构造器):构造这个类的对象。

Producer(生产器):利用这个类的对象,通过某些操作创建一个新的这个类的对象。

Observer(观察器):观察对象的属性等。

Mutator(变值器):改变对象的值。不变对象没有mutator。

表示独立性 RI representation independent

client使用ADT时无需考虑其内部如何实 现,ADT内部表示的变化不应影响外部spec和客户端。除非ADT的操作指明了具体的pre和post-condition,否则不能改变ADT的内部表示——spec规定了client和implementer之间的契约。

不变量 Invariants

在任何时候总是true。由ADT 来负责其不变量,与client端的任何行为无关。

表示泄露 representation exposure

不仅影响不变性,也影响了表示独立性:无法在不影响客户 端的情况下改变其内部表示。使用immutable的类型,彻底避免表示泄露。

RI、AF、Safety from rep exposure

表示空间R:ADT实现者关注的空间。

抽象空间A:用户关注的空间。

AF : R → A

RI : R → boolean 某个具体的“表示”是否是“合法的”,也可看作所有表示值的一个子集,包含了所有合法的表示值,也可看作一个条件,描述了什么是“合法”的表示值。

选择某种特定的表示方式R,进而指定某个子集是“合法”的(RI),并为该子集中的每个值做出“解释”(AF)——即如何映射到抽象空间中的值。

即使是同样的R、同样的RI,也 可能有不同的AF,即“解释不同”。

//Rep Invariant:
//    所有合法的表示值/一个描述合法表示值的条件
//Abstraction Function:
//    从R到A的映射
//Safety from rep exposure
//    描述是如何防止表示泄露的
在ADT中使用checkRep()来随时检查RI是否满足。

OOP

类 Class

下面为一个简单的类的例子:

public class Person {
    //类成员变量
    private String name;
    private String sex;
    private int age;

    //类方法
    Person(String name, String sex, int age) {    //Creator
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
     
    int howOld() {    //Observer
        return this.age;
    }
    void setAge(int age) {    //Mutator
        this.age = age;
    }
    ......
}

接口 interface

定义一个ADT。接口中只有方法的声明,一个接口可以有多种实现类,接口之间可以继承。

下面为一个接口InterName和这个接口的实现类ClassName的例子:

public interface InterName {
    ReturnType method1();
    ReturnType method2(AttrType attr, ...);
    ......
}
public class ClassName implements InterName {
    Type1 var1;
    Type2 var2;

    public InterName(Type1 var1, Type2 var2) {
        this.var1 = var1;
        this.var2 = var2;
    }
     
    ReturnType method1() {......}
    ReturnType method2(AttrType attr, ...) {......}
    ......
}

Overriding(覆盖/重写)

根据子类中不同的需要,重写父类中的方法。

Overloading(重载)

重载:多个方法具有同样的名字,但有不同的参数列表或返回类型,方便根据具体情况调用。

重载规则:必须有不同的参数列表,返回值可相同可不同,访问修饰符可相同可不同,可以有新的异常,可以再一个类内重载,也可以在子类中重载。

equals()、hashCode()和toString()

在自定义的类中,需要重写这三个方法来保证结果正确。(toString()一般是根据程序员自己定义的格式写的,没有标准)

==和equals()的区别:==判断两个对象是否指向内存中同一段空间,而缺省的equals()判断两个对象是否指向同一个引用,但我们使用equals()时通常是为了判断两个对象是否相同,所以就需要重写。

对可变类型,实现行为等价性即可,所以无需重写这两个函数,直接继承Object即可。

一个例子:

public class Person {
    private String name;
    private String sex;
    private int age;

    @Override
    public boolean equals(Object o) {
        if(!(o instanceof Person)) {
            return false;
        }
        Person pe = (Person) o;
        return pe.name.equals(this.name) && pe.sex.equals(this.sex) && pe.age.equals(this.age);
    }
     
    @Override
    public int hashCode() {
        return 31 * this.name.hashCode() + 31 * this.sex.hashCode() + age;
    }
     
    @Override
    public String toString() {
        return "[name]"+this.name+"[sex]"+sex+"[age]"+age;
    }
     
    ......
}

泛型接口

其定义中包含类型变量(例如public interface Set),既不定义数据类型,在实现时根据需要设定数据类型。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LredCoat

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值