Skip to content

Latest commit

 

History

History
55 lines (51 loc) · 4.7 KB

readme.md

File metadata and controls

55 lines (51 loc) · 4.7 KB

1.2 节主要讲解数据抽象相关的东西。

  1. 为什么会出现数据抽象的概念?

    • 如果只有原始的数据类型,那我们的程很大程度上会被限制在只做些算术运算上,无法操作字符串、图像声音和各种各样的庞大数据。
    • 某种程度上说,数据抽象也是和面向对象编程的思想相互依存。要想实现数据抽象,就需要支持数据类型的自定义,面向对象编程的思想正好可以满足。或者说,正是出于对各种数据进行抽象的需要,所以有了面向对象编程的思想?
  2. 什么是数据抽象?

    • 将数据和函数关联起来,并将数据的表示方法对使用者隐藏起来的表示方式。在使用抽象数据类型时,我们的注意力几种在 API 描述的操作上而不会去关心数据的表示。在实现抽象数据类型时,我们的注意力集中在数据本身并实现对该数据的各种操作。例如 java 中的数组、字符串等类型,就是数据抽象,我们并不关心内部是如何存储数据的,我们只是通过暴露出来的 API 操作数据。
    • 对象的三大关键性质:
      • 状态:即数据类型中的值
      • 标识:唯一区分对象的标识符,许多时候我们都通过内存中的位置来进行区分
      • 行为:操作数据的方法
  3. 如何实现数据抽象?

    知道了什么是数据抽象之后,那如何自定义抽象数据类型呢?说人话就是如何实现自定义的类,需要以下几个主要元素:

    • 实例变量:存储每个对象的状态,包括不同作用域类型的变量
    • 构造函数:初始化对象的状态并创建一个对象的标识
    • 实例方法:定义每个对象的行为。包括 API 与实现的定义
  4. 设计数据类型时需要注意的点。

    • 封装。封装有许多好处,可以保持各个模块之前的独立性。
    • 设计 API。这应该是现如今写代码最有挑战性的一项任务了。常见的 API 设计陷阱:
      • 难以实现
      • 难以使用,使用 API 甚至比不使用代码上还要复杂
      • 范围太窄,缺少需要的方法
      • 范围太宽,包含许多不会被使用的方法。这种缺陷可能比较常见,因为新增方法很简单,删除方法却很困难
      • 太粗略,无法提供有效的抽象
      • 太详细,国语细致或发散导致无法使用
      • 太过于依赖某种特定的数据表示,这种缺陷也比较难以避免,因为数据表示是数据抽象类型实现的核心
    • 算法与抽象数据类型
    • 接口继承,即接口实现,通过接口联系两个没有交集的类
    • 实现继承,即平常所说的子类。但是另一方面,子类继承也会影响模块化编程,原因有两点:
      • 父类的任何改动都会影响它的所有子类
      • 子类代码可以访问所有实例变量,因此可能会扭曲父类代码的意图
    • 字符串表示的习惯
    • 封装类型,内置的数据类型
    • 等价性,如何判定两个对象相等
    • 内存管理,对象为引用数据类型,如何在必要时及时释放内存
      • 原始数据类型生命周期单一,出了作用域后直接释放就可以
      • 引用数据类型生命周期不确定。C/C++ 的手动释放和java 的垃圾回收机制
    • 不可变性
      • 不可变的数据类型比可变的数据我俩看使用更容易,误用更困难,因为能够改变它们的值的方式少,调试起来也更简单。但不可变性的缺点有:一、需要为每个值创建一个新对象,二、java 中的 final 只能用来保证原始数据类型的实例变量的不可变性,但无法确保实例变量所引用的对象的值不可变
    • 契约式设计,即异常和断言