第 20 章:进阶编程

你好,欢迎来到“进阶编程”部分!在这里,我们将深入探讨那些使现代软件变得稳健且可扩展的高级哲学与技术。如果某些概念起初看起来比较抽象,请不要担心——我们将带你逐一拆解这些强大的概念,例如从全新的角度看待编程(编程范式),以及如何处理突发的意外情况(异常处理)。掌握这一章的内容,将助你从一名合格的程序员蜕变为一名高级软件设计师!


20.1 编程范式

编程范式 (Programming Paradigm) 本质上是一种编写计算机程序的根本风格或方法论。它是一种哲学,决定了程序员如何构建代码以及如何看待他们试图解决的问题。

本大纲要求理解四种主要的范式:低级语言、命令式(过程式)、面向对象和声明式。

1. 低级编程范式 (Low-Level Programming Paradigm)

这种范式涉及编写非常接近计算机原生语言(机器码)或人类可读性稍好的版本(汇编语言)的指令。

  • 特征: 低级代码专注于直接的硬件控制、内存地址和寄存器。它精确地告诉 CPU 下一步要执行的具体微观步骤。
  • 应用: 用于对执行速度、内存占用有极高要求,或需要直接操作硬件(如控制嵌入式系统或设备驱动程序)的场景。
关键概念:寻址方式(4.2 节回顾)

编写低级代码时,必须指明 CPU 如何找到所需数据。以下是几种寻址方式:

  1. 立即寻址 (Immediate Addressing): 操作数本身就是数据。
    示例:LDM #10(将数值 10 直接加载到累加器中)。
  2. 直接寻址 (Direct Addressing): 操作数是数据存储的内存地址
    示例:LDD 500(加载地址 500 处存储的内容)。
  3. 间接寻址 (Indirect Addressing): 操作数是一个地址,该地址中存储的是数据的实际地址(指针)。
    示例:LDI 600(访问地址 600,读取其中的值,假设为 800,然后再访问地址 800 并加载该内容)。
  4. 变址寻址 (Indexed Addressing): 通过操作数地址加上变址寄存器 (IX) 的内容来计算有效地址。非常适合遍历数组。
    示例:LDX 400(有效地址 = 400 + IX 的内容)。
  5. 相对寻址 (Relative Addressing): 通过将操作数与程序计数器 (PC) 的内容相加来计算地址。常用于跳转指令,使代码具有位置无关性。
重点总结(低级语言): 核心在于效率和直接控制。当被要求使用此范式编写代码时,必须正确应用特定寻址方式的语法(例如使用 # 表示立即寻址)。

2. 命令式(过程式)编程范式 (Imperative/Procedural Paradigm)

这是你在 AS 阶段重点学习的“经典”结构化方法。它将计算定义为一系列改变程序状态(变量)的语句。

  • 特征: 侧重于程序如何运行。它使用结构化编程概念:顺序、选择(IF/CASE)和迭代(循环)。问题通过模块化解决:过程 (Procedures)(执行动作)和函数 (Functions)(返回结果)。
  • 必备技能: 必须能够熟练运用变量、常量、所有控制结构、过程和函数编写代码(包括按值传递和按引用传递参数)。
你知道吗? “命令式”一词源于“祈使句”(Imperative sentence),意为命令。你在一步步地向计算机下达命令。

3. 面向对象编程 (OOP) 范式

OOP 将程序视为相互作用的对象 (objects) 的集合。其目标是在程序中模拟现实世界的事物,使代码更易于复用和维护。

OOP 核心术语
  1. 类 (Class): 创建对象的蓝图或模板。它定义了该类型所有对象共享的结构(属性)和行为(方法)。
    类比:汽车工厂的图纸。
  2. 对象 (Object / Instance): 由类创建的具体的、实体的实例。
    类比:你那辆根据汽车图纸制造出来的红色本田汽车。
  3. 属性 (Property / Attribute): 定义对象状态的数据或特征(类内部的变量)。
    示例:汽车的 颜色速度排量
  4. 方法 (Method): 对象可以执行的动作或功能。
    示例:汽车的 启动引擎()加速()刹车()
  5. 封装 (Encapsulation): 将数据(属性)与操作这些数据的方法绑定在一个单元(对象)中,并隐藏内部细节的原则。
  6. Getter 和 Setter: 用于控制对属性访问的特殊方法,以维护封装性。Getter 用于获取(读取)属性值;Setter 用于修改(写入)属性值,通常包含验证检查。
  7. 继承 (Inheritance): 一种基于现有类(超类/父类)创建新类(子类)的机制。子类自动继承父类的所有属性和方法,从而提升代码复用性。
    示例:卡车类继承自车辆类。
  8. 多态 (Polymorphism): 意为“多种形式”。它允许不同类的对象对同一个方法调用做出适合其自身类的响应。
    示例:对象可能都有 发出声音() 方法,但狗会汪汪叫,而猫会喵喵叫。
  9. 聚合/包含 (Containment / Aggregation): 当一个类的属性是另一个类的对象时。它代表一种“拥有(has-a)”的关系。
    示例:汽车拥有一个引擎对象。
记忆口诀(OOP 四大支柱): 记住 A PIE(抽象 Abstraction、多态 Polymorphism、继承 Inheritance、封装 Encapsulation),这是 OOP 的核心优势;但在定义时,别忘了加上类、对象和包含关系!

4. 声明式编程范式 (Declarative Programming Paradigm)

该范式侧重于定义结果应该是什么,而不是罗列达成结果的每一步指令(“如何做”)。它通常依赖于事实 (facts) 和规则 (rules)

  • 特征: 程序是一组逻辑语句(事实)和关系(规则)。系统会尝试利用这些定义来达成既定的目标 (goal)
  • 与命令式的对比:
    • 命令式: “从 A 到 B,首先向左转,然后直行,再向右转……”(分步骤过程)。
    • 声明式: “A 是终点,B 是起点,寻找一条有效路径。”(定义目标,让语言引擎去寻找实现路径)。
  • 必备技能: 需要理解如何通过编写适当的事实和规则来解决问题,并展现出能够编写满足特定目标代码的能力(通常在 Prolog 或高级 SQL 查询中可见)。
重点总结(范式): 核心区别在于焦点不同:低级(硬件步骤)、命令式(步骤指令)、OOP(现实世界对象的交互)、声明式(逻辑事实与目标)。

20.2 文件处理与异常处理

文件处理对于永久性数据存储至关重要。当程序超出简单的输入/输出需求时,你需要稳健的方法来管理数据的存储、检索,并妥善应对意外情况。

1. 文件处理操作

你必须能够编写代码执行标准的文件处理操作:

A. 文件的打开与关闭

在读取或写入之前,必须以特定的模式 (mode) 打开文件:

  • 读取模式 (Read Mode): 允许从文件中检索数据。如果文件不存在,通常会报错。
  • 写入模式 (Write Mode): 允许向文件中写入数据。如果文件已存在,其原有内容通常会被覆盖(删除)。
  • 追加模式 (Append Mode): 允许将新数据添加到现有文件的末尾。现有内容会被保留。

所有操作完成后,必须关闭文件,以确保数据完整性并释放系统资源。

B. 文件组织与访问方法

文件的存储方式会影响你查找特定数据的速度。

  1. 串行文件 (Serial File): 记录按照创建顺序依次存储。它们被顺序访问。要找到第 100 条记录,必须先读过前 99 条记录。
  2. 顺序文件 (Sequential File,使用键字段): 记录根据键字段 (key field)(如姓氏的字母顺序)按特定顺序存储。访问通常是从头开始顺序读取,直到匹配到键为止。
  3. 随机文件 (Random File): 无需读取之前的记录即可直接访问记录。通过公式(或键值映射)计算出记录在磁盘上的确切物理位置(地址)。这允许极快的数据检索。

在编写文件处理代码时,记住你必须能够对整个记录 (record)(通常对应代码中定义的记录结构或类对象)进行读写。

2. 异常处理的重要性

在实际编程中,意外事件随时可能发生:网络中断、用户输入非数字字符、磁盘空间耗尽等。一个在出错时直接崩溃的程序是不专业且不可靠的。

定义与重要性
  • 异常 (Exception) 是程序运行期间发生的中断正常指令流的事件,通常表现为运行时错误。
  • 异常处理的重要性:
    • 防止程序突然崩溃(终止)。
    • 允许程序“优雅地”失败,并向用户提供有用的反馈。
    • 让开发者有机会从错误中恢复(例如重试网络连接或正确关闭文件)。
何时使用异常处理

每当代码逻辑依赖于外部资源或无法严格控制的用户操作时,都应使用异常处理。常见情况包括:

  • 尝试打开不存在的文件(File Not Found)。
  • 尝试连接不可用的数据库或网络。
  • 计算产生未定义的数学状态(如除以零)。
  • 尝试将数据转换为不兼容的类型(如将“hello”转换为整数)。
异常处理的代码实现

基本结构通常包括一个受保护的代码块(TRY)和一个在错误发生时执行的块(CATCHEXCEPT)。

示例结构(伪代码概念):
TRY
    OPENFILE("data.txt", READ)
    // 正常处理代码在此处
CATCH (FileNotFoundError)
    OUTPUT "错误:数据文件未找到,请检查磁盘。"
END TRY

回顾(异常): 如果 TRY 块内发生错误,程序会立即停止执行该块,跳转到 CATCH 块,从而实现受控响应,避免系统直接崩溃。