第五章 抽象一:封装
第五章 抽象一:封装
大型程序的构造中,程序员不可避免要涉及到新数据类型的设 计和实现 如:大学中,表示一堂课的数据对象 section,包含的信息有: 老师名、教室、最大注册数等,还可以包含一个注册学生列 表作为部件 操作包括:创建一个 section、注册一个学生、消除一个 sectior寺。 其实现主要涉及其表示以及对应相关操作的子程序设计 语言实现的目标是使得数据的各种形式的不同对程序员透明 因此,基本类型和用户定义类型对程序员的使用来说应不存在 差别
•大型程序的构造中,程序员不可避免要涉及到新数据类型的设 计和实现。 如:大学中,表示一堂课的数据对象section,包含的信息有: 老师名、教室、最大注册数等,还可以包含一个注册学生列 表作为部件。 操作包括:创建一个section、注册一个学生、消除一个 section等。 其实现主要涉及其表示以及对应相关操作的子程序设计。 •语言实现的目标是使得数据的各种形式的不同对程序员透明。 因此,基本类型和用户定义类型对程序员的使用来说应不存在 差别
有三种机制可被程序员用来创建新类型和类型上的操作。 、子程序:可用子程序来定义实现类型的操作,但如何正 确地使用,却是程序员的责任 2、类型声明:语言包含有定义新类型及其操作的能力。抽 象数据类型即是这种机制,它提供了检测错误使用的能力 3、继承:基于已有类型创建新类型的机制
•有三种机制可被程序员用来创建新类型和类型上的操作。 1、子程序:可用子程序来定义实现类型的操作,但如何正 确地使用,却是程序员的责任。 2、类型声明:语言包含有定义新类型及其操作的能力。抽 象数据类型即是这种机制,它提供了检测错误使用的能力。 3、继承:基于已有类型创建新类型的机制
51抽象数据类型 数据类型概念的演化 早期类型定义为值的集合,该类型的变量可在该集合中取值 70年代初, Pascal扩展类型定义为:变量的集合。 70年代早期,概念进一步演化,类型不仅仅是类型对象的集 合,还包含了其相关操作。正是操作展示了对象的行为。 例:对基本类型实数和整数,语言提供了声明机制和相 关操作。从而其存储表示被封装,程序员使用它们而不 需知道表示细节 数据抽象——以数据为中心的封装方式 ADT定义为 组数据对象,通常使用一个或多个类型定义 2、一组对这些对象的抽象操作。 3、二者的封装,使得该类型的用户只能通过这些操作来 操纵该类型的数据对象
5.1 抽象数据类型 数据类型概念的演化 早期类型定义为值的集合,该类型的变量可在该集合中取值。 70年代初,Pascal扩展类型定义为:变量的集合。 70年代早期,概念进一步演化,类型不仅仅是类型对象的集 合,还包含了其相关操作。正是操作展示了对象的行为。 例:对基本类型实数和整数,语言提供了声明机制和相 关操作。从而其存储表示被封装,程序员使用它们而不 需知道表示细节。 •数据抽象——以数据为中心的封装方式 ADT定义为: 1、一组数据对象,通常使用一个或多个类型定义。 2、一组对这些对象的抽象操作。 3、二者的封装,使得该类型的用户只能通过这些操作来 操纵该类型的数据对象
信息隐蔽 “分而治之”是我们编写大型程序的一般策略,程序被分成 模块。 模块设计有两种途径:①功能分解,②数据分解。 然而,功能设计有一定缺陷,不能对数据结构的细节提供 很好隐蔽。 而使用数据抽象可以避免这些问题。 数据类型的规约给出了所有使用该类型对象所需要的信息, 而实现细节则对外屏蔽。 ·“抽象”在语言中是一个重要概念,语言以两种方式提供对 抽象的支持。首先,提供一个抽象虚拟机,它比实际计算机 更易于使用,也更强大,语言直接提供了一些有用的抽象, 称为语言的特性;第二,语言提供了辅助程序员定义抽象的 设施,这些抽象形成了特定程序定义的抽象机
信息隐蔽 •“分而治之”是我们编写大型程序的一般策略,程序被分成 模块。 模块设计有两种途径:①功能分解,②数据分解。 然而,功能设计有一定缺陷,不能对数据结构的细节提供 很好隐蔽。 而使用数据抽象可以避免这些问题。 •数据类型的规约给出了所有使用该类型对象所需要的信息, 而实现细节则对外屏蔽。 •“抽象”在语言中是一个重要概念,语言以两种方式提供对 抽象的支持。首先,提供一个抽象虚拟机,它比实际计算机 更易于使用,也更强大,语言直接提供了一些有用的抽象, 称为语言的特性;第二,语言提供了辅助程序员定义抽象的 设施,这些抽象形成了特定程序定义的抽象机
信息隐蔽是程序定义抽象设施的设计的中心原则 每个程序部件应尽可能对用户隐藏信息。 ·当信息被封装在抽象中时,意味着抽象的用户 为了使用该抽象,不需要知道隐蔽的信息 2、不允许直接使用或操纵被隐蔽的信息,即使用户希望 这么做。 例如: Fortran、 Pascal中的整数类型不仅隐蔽了整数的表 示细节,甚至有效地封装了表示,使得程序员不能操作整 数中的个体位。 但它们难于封装新数据类型的表示,虽然也可以构造子程 序集合来创建和操作抽象,但不能真正封装其表示,程序 员可以编写其他子程序来非法地或不合适地操作抽象。 封裝对使程序易于修改特別有用,只要保持子程序(操作) 接口不变即可。 °注意:信息隐蔽是一个程序设计问题,和语言无关。封装则 是语言设计问题。抽象被有效封装的前提是有机制防止外界 对抽象中隐蔽信息的访问
•信息隐蔽是程序定义抽象设施的设计的中心原则 ——每个程序部件应尽可能对用户隐藏信息。 •当信息被封装在抽象中时,意味着抽象的用户: 1、为了使用该抽象,不需要知道隐蔽的信息。 2、不允许直接使用或操纵被隐蔽的信息,即使用户希望 这么做。 例如:Fortran、Pascal中的整数类型不仅隐蔽了整数的表 示细节,甚至有效地封装了表示,使得程序员不能操作整 数中的个体位。 但它们难于封装新数据类型的表示,虽然也可以构造子程 序集合来创建和操作抽象,但不能真正封装其表示,程序 员可以编写其他子程序来非法地或不合适地操作抽象。 •封装对使程序易于修改特别有用,只要保持子程序(操作) 接口不变即可。 •注意:信息隐蔽是一个程序设计问题,和语言无关。封装则 是语言设计问题。抽象被有效封装的前提是有机制防止外界 对抽象中隐蔽信息的访问
52通过子程序封装 子程序是程序员定义的抽象操作—是大多数程序的基本建 筑块。对子程序可从两个方面来看: 在程序设计级——子程序表示程序员定义的抽象操作。 在语言设计级—涉及子程序设施的设计和实现。 子程序作为抽象操作 子程序的规约和实现均由程序员提供, 子程序的规约 包括: 1、子程序的名字 2、子程序的基调 3、子程序的动作 和基本原操作类似
5.2 通过子程序封装 子程序是程序员定义的抽象操作——是大多数程序的基本建 筑块。对子程序可从两个方面来看: 在程序设计级——子程序表示程序员定义的抽象操作。 在语言设计级——涉及子程序设施的设计和实现。 子程序作为抽象操作 子程序的规约和实现均由程序员提供。 •子程序的规约 包括: 1、子程序的名字 2、子程序的基调 3、子程序的动作 和基本原操作类似
函数子程序—显示地返回单个结果数据对象。 基调为:FN:rea× Integer→real 过程式子例程—返回多个结果,或修改参数而不是显式地返 回结果。如:C语言中: void Sub(float X, int Y, float*Z, int *W) 无显式返回,*表示指针,可以被修改的参数。 AdaH: procedure Sub(X: in REAL; Y: in integer Z: inout REAL; w: out Boolean) 其基调为:Sub:real× integer X real2-real3× Boolean in和ou指出参数的性质。 当子程序表示数学函数,如何精确地描述其功能有如下问题: 、子程序可能有隐式参数(以非局部变量形式) 2、子程序可能有隐式结果(副作用)(对非局部变量和in- ou参数) 3、可能对某些可能的参数没有定义。 4、子程序是历史敏感的
函数子程序——显示地返回单个结果数据对象。 基调为:FN:real×integer→real 过程式子例程——返回多个结果,或修改参数而不是显式地返 回结果。如:C语言中: void Sub(float X, int Y, float * Z, int *W); 无显式返回, *表示指针,可以被修改的参数。 Ada中:procedure Sub (X: in REAL; Y: in integer; Z: inout REAL; W: out Boolean) 其基调为:Sub: real1×integer×real2→real3×Boolean in和out指出参数的性质。 当子程序表示数学函数,如何精确地描述其功能有如下问题: 1、子程序可能有隐式参数(以非局部变量形式) 2、子程序可能有隐式结果(副作用)(对非局部变量和inout参数) 3、可能对某些可能的参数没有定义。 4、子程序是历史敏感的
子程序的实现 一个子程序表示了由程序员构造的虚拟机层次上的一个操 作。这样,子程序用程序语言本身提供的数据结构和操作 来实现 子程序的实现用子程序体定义。包括: 局部数据声明——定义局部结构或数据 句——定义动作 封装保证:局部数据和语句不可被用户单独访问,只 能通过传入参数而调用子程序 有些语言中,Body中也允许其他子程序的定义。 子程序调用需要合适类型的参数,因此,类型检查也是需 要的。类型检查和基本操作类似处理
•子程序的实现 一个子程序表示了由程序员构造的虚拟机层次上的一个操 作。这样,子程序用程序语言本身提供的数据结构和操作 来实现。 子程序的实现用子程序体定义。包括: 局部数据声明——定义局部结构或数据; 语句——定义动作。 封装保证:局部数据和语句不可被用户单独访问,只 能通过传入参数而调用子程序。 有些语言中,Body中也允许其他子程序的定义。 子程序调用需要合适类型的参数,因此,类型检查也是需 要的。类型检查和基本操作类似处理
子程序定义和调用 ·子程序定义和子程序激活 子程序定义描述程序的静态性质,在执行中,如子程序 被调用,则子程序的一个激活被创建,当子程序执行结 果,则激活被消除,因此,定义作为创建执行过程中激 活的模板。 定义和激活的不同是重要的。 定义是程序的语法成分,其信息只是在翻译时所用信息 (如变量类型,但其左、右值并不知道) 激活在执行时存在(可访问左值、执行右值,但类型不 再可用,除非描述子)
子程序定义和调用 •子程序定义和子程序激活 子程序定义描述程序的静态性质,在执行中,如子程序 被调用,则子程序的一个激活被创建,当子程序执行结 果,则激活被消除,因此,定义作为创建执行过程中激 活的模板。 •定义和激活的不同是重要的。 定义是程序的语法成分,其信息只是在翻译时所用信息 (如变量类型,但其左、右值并不知道)。 激活在执行时存在(可访问左值、执行右值,但类型不 再可用,除非描述子)