06-交互形态下其他流的变化
交互形态下其他流的变化——控制流/错误流/反馈流/状态流
从输入到交互主线的五篇分别讲五种交互形态的用户流程(用户操作什么、得到什么)。但同一批交互形态下,还有四条其他流也在演化:控制流(程序往哪走)、错误流(出错怎么办)、反馈流(发现问题回退到哪)、状态流(跨操作记住什么)。它们散落在五篇各节里,本篇把它们合并成一条流:按流纵向追踪,五种形态横向对比。
一、为什么需要分离
五篇主线的焦点是用户流程:用户可感知的操作序列。
1 | 无交互CLI:输入 → 等待 → 结果 → 结束 |
四条其他流在同样的形态变迁中各自演化,但不是「用户做了什么」,而是「程序内部/程序与用户之间发生了什么」:
1 | 控制流 —— 程序走向由谁决定:程序自己?用户?事件?多进程? |
下面按流追踪,每种流给出「五种形态 × 演化」的纵向变化。
二、控制流:控制权的五级迁移
控制流问的是:程序往哪走、下一步执行什么,由谁决定?
| 形态 | 控制权在谁手里 | 程序结构 |
|---|---|---|
| 无交互 CLI | 程序自己 | 直线:main → 解析 → 执行 → 退出 |
| 有交互 CLI | 用户驱动循环 | 命令循环:等待输入 → 解析 → 执行 → 等待输入 |
| TUI | 焦点驱动 | 事件循环:等待按键 → 按当前焦点分发 → 重绘 |
| GUI | 事件驱动 | 事件循环:等待事件 → 找到控件 → 调用处理 → 重绘 |
| 多系统 GUI | 分布式事件 | 事件循环 + 跨进程回调(外部进程完成后通知 GUI) |
1 | 控制权迁移主线: |
关键节点:
- 有交互 CLI:命令循环掌握程序骨架,但「执行什么命令」由用户输入决定——用户是控制流的源头。
- TUI:控制权进一步细化到焦点——同一个按键在不同焦点下有不同含义(↑在列表=上移,在详情=上滚)。焦点决定用户输入流向哪个区域。
- GUI:控制权变成事件分发——鼠标/键盘/系统事件沿控件树查找目标控件,事件处理完更新界面。
- 多系统 GUI:控制权部分跨出进程(外部进程完成后 → 通知 → GUI 更新),主流程仍是 GUI 事件循环。
控制流结论:随着交互形态变复杂,控制权从「程序自己」一步步交出去,最终是「事件 + 回调」分布式决定程序走向。
三、执行流:程序内部的运行结构
执行流问的是:程序内部实际怎么一步步运行?
| 形态 | 程序执行结构 |
|---|---|
| 无交互 CLI | 一条直线:启动 → 解析参数 → 执行 → 输出 → 退出 |
| 有交互 CLI | 初始化 → 命令循环(读行→解析→执行→循环)→ 退出 |
| TUI | 初始化终端 → 绘制初始屏幕 → 事件循环(等待输入→分发→重绘)→ 恢复终端 |
| GUI | 创建窗口/控件树 → 事件循环 → 销毁窗口 |
| 多系统 GUI | 创建窗口 → 连接外部进程 → 事件循环 → 异步请求/回调 → 通知 → 退出 |
1 | 执行结构演化: |
每当交互从「处理一行输入」变成「处理一个输入」,执行流的循环粒度就细一级:
1 | 有交互CLI:一次一个命令行(行级) |
执行流与用户流程交界:用户流程描述「用户端发生了什么」,执行流描述「程序端怎么运行」。两者只在两端碰头(无交互 CLI 只在启动/退出碰头;GUI 之后每次交互都碰头)。
四、错误流:出错之后的处理方式
| 形态 | 出错后 | 结果 |
|---|---|---|
| 无交互 CLI | 输出错误 → 退出(非零退出码) | 程序结束 |
| 有交互 CLI | 输出错误 → 回到命令循环 | 程序继续 |
| TUI | 输出错误 → 刷新屏幕 → 回到等待 | 程序继续 |
| GUI | 弹错对话框/状态栏错误 → 回到事件循环 | 程序继续 |
| 多系统 GUI | 外部进程错误(编译失败等)→ IPC 传给 GUI → 界面提示 → 回到事件循环 | 程序继续 + 跨进程传播错误 |
错误流的第一次质变在有交互 CLI:
1 | 无交互:出错 → 退出 → 用户重新输入完整命令(新进程) |
错误不再终止程序,程序要能从错误中恢复、继续处理下一条命令。
第二次质变在多系统:错误开始跨进程传播——
1 | 外部进程(编译失败)→ 生成错误信息 → IPC 发给 GUI → 控件状态变化 → 用户看到错误 |
错误处理的层次也随之分层:
1 | 无交互:程序自己决定(错误码) |
五、状态流:会话要记住什么
状态流问的是:这次交互之间,程序需要记住什么?
| 形态 | 状态 | 形态 |
|---|---|---|
| 无交互 CLI | 无状态 | 每次调用独立,无记忆,无上下文 |
| 有交互 CLI | 会话状态 | 跨命令共享信息(scan → goto 记住偏移) |
| TUI | 空间状态 | 布局/焦点/区域内容/滚动位置/模态 |
| GUI | 树状状态 | 窗口状态 + 控件状态(对应控件树) |
| 多系统 GUI | 分布式状态 | GUI 状态 + 外部进程状态 + 同步状态 |
从无到有的第一级:
1 | 无交互:无状态(每次调用独立) |
会话状态有三种形态:全局状态(设置一次全程生效)、上下文状态(工作目录可切换)、临时状态(本次命令有效)。
从单层到多层:
1 | 有交互:全局 + 文档上下文 |
状态流与用户流的区分:用户流强调「用户操作序列」,状态流强调「程序内部为了让操作连续而记住什么」。
六、反馈流:发现问题回顾到哪
反馈流问的是:发现不对之后,回到哪一步重新做?
| 形态 | 反馈方式 | 回退点 |
|---|---|---|
| 无交互 CLI | 反馈几乎不存在 | 出错 → 退出 → 用户重新输入完整命令(跨进程重来) |
| 有交互 CLI | 首次真正实现 | 程序内部 → 用户介入修正 → 同一进程继续 |
| TUI | 即时反馈 | 按键 → 界面立即更新(不需要按回车) |
| GUI | 批判的视觉反馈 | 点击 → 控件状态变化 → 屏幕更新(立即) |
| 多系统 GUI | 跨进程反馈 | 用户 → GUI → 外部进程 → 错误传回 → GUI 显示 → 用户修正 → 再执行 |
反馈流第一次成形是有交互 CLI(此前只是错误处理,不是反馈):
1 | 扫描失败 → 看错误信息 → 修正命令 → 重新执行(同一会话内完成闭环) |
反馈流从「用户可回退」到「用户+界面即时回退」再到「多个实体跨进程回退」——
1 | 无交互:不存在的反馈(走到黑,重来就是新进程) |
反馈流的强弱 = 软件组织成熟度的标尺:能回退的步进越小、回退越即时,人机协同就越流畅。
七、退出流:生命周期怎么结束
| 形态 | 退出方式 |
|---|---|
| 无交互 CLI | 程序执行完自动退出(return 0 / 错误返回非零) |
| 有交互 CLI | 用户输入 exit / Ctrl+C / 程序异常(四机) |
| TUI | 用户按退出键(q/Esc),恢复终端 |
| GUI | 用户点击关闭按钮 → 销毁窗口 |
| 多系统 GUI | 用户关窗口 → 通知外部进程 → 外部进程退出 → 程序退出 |
多个交互形态的退出权在用户手里(有交互 CLI 之后完全用户主导),多系统最复杂的地方在退出前需要通知/清理外部进程。
1 | 无交互:生命周期 = 程序执行完即结束 |
八、五形态 × 四条流一览
1 | 无交互CLI 有交互CLI TUI GUI 多系统GUI |
全部六条流的质变基本都发生在同几个点:
1 | 第一次质变:无交互 → 有交互(控制权转移给用户、会话状态出现、错误可恢复) |
九、结论:用户流程主线 + 其他流纵向线
[]从输入到交互主题的完整视图是两条正交的线:
1 | 用户流程线(五篇):无交互 → 有交互 → TUI → GUI → 多系统GUI |
从输入到交互主题 = 用户流程(五篇) + 其他流的变化(本篇),两者都按「无交互 → 多系统」的顺序演化,但一个是用户视角,一个是程序视角。
