KWIC 与软件架构案例分析
北京大学软件与微电子学院 周立新《软件体系结构》课程 Lecture-3 案例研究 4 个 Case Study:KWIC 索引系统 / 机器人控制系统 / (Case Study 3 待补充) / 巡航控制系统
一、Case Study 1:KWIC 索引系统
1.1 问题定义
KWIC(Key Word In Context)索引系统 [Parnas 1972] 是软件架构领域的经典教学案例:
- 输入:一组有序的行(每行是有序的单词集合,每个单词是有序的字符集合)
- 核心操作:对每行进行循环移位(circular shift)——不断将第一个单词移到行尾
- 输出:所有行的所有循环移位,按字母顺序排列的列表
这是 D.L. Parnas 在其经典论文 “On the Criteria To Be Used in Decomposing Systems into Modules” (1972) 中使用的案例,用于说明不同分解策略对系统可变性的影响。
1.2 评估维度(潜在变化)
一个好的架构应该能从容应对以下五类变化:
| 变化维度 | 说明 |
|---|---|
| 算法变化 | 循环移位的时机:读入时即时移位 / 全部读入后统一移位 / 字母排序时按需移位 |
| 数据表示变化 | 行/单词/字符的存储方式;循环移位是显式存储还是隐式表示(索引+偏移对) |
| 功能增强 | 排除噪声词(noise words);支持交互式查询 |
| 性能 | 减少空间和时间消耗 |
| 复用性 | 组件在多大程度上可作为可复用实体 |
1.3 四种架构方案对比
方案一:主程序/子程序 + 共享数据(Main Program/Subroutine with Shared Data)
结构:Master Control 主程序协调 Input → Circular Shift → Alphabetizer → Output 四个子程序,通过共享数据区(字符数组 + 索引数组)交换数据。
- 优点:
- 数据表示效率高(直接内存访问)
- 计算任务模块化清晰
- 缺点:
- 对任何变化都不友好:
- 数据表示变化 → 影响所有模块
- 算法变化 → 影响所有模块
- 不利于组件复用
- 对任何变化都不友好:
这是典型的功能分解(functional decomposition),按处理步骤切分系统,模块间通过全局数据耦合,变更成本最高。
方案二:抽象数据类型(Abstract Data Types)
结构:输入/输出模块与处理模块(Circular Shift / Alphabetic Shifts)通过子程序调用 + 接口交互,数据封装在各模块内部。
- 优点:
- 算法和数据表示可独立变更(封装在模块内部)
- 复用机会更多(接口稳定)
- 缺点:
- 难以应对某些功能增强:
- 新增功能意味着修改接口
- 或新增模块但会影响性能
- 功能变更的”涟漪效应”比共享数据小,但仍然存在
- 难以应对某些功能增强:
这是面向对象分解(OO decomposition),按数据抽象切分系统,封装性优于功能分解,但新增功能仍需修改已有接口。
方案三:隐式调用(Implicit Invocation)
结构:Master Control 主控 + Input / Shifter / Sorter / Output 各模块通过事件广播交互——一个模块发布事件,其他模块监听并响应。数据(Lines)通过事件携带或共享。
- 优点:
- 功能增强容易:只需新增监听事件的模块
- 复用性好(模块间松耦合)
- 缺点:
- 难以协调处理顺序(事件触发顺序不确定)
- 空间和时间开销增加(事件机制本身的成本)
这是事件驱动/观察者模式的架构变体,新增功能时对已有代码改动最小。
方案四:管道过滤器(Pipes and Filters)
结构:Input → Circular Shift → Sorter → Output 四个过滤器通过管道串行连接,数据流式流过各阶段。
- 优点:
- 直观易懂(数据流视角)
- 复用性好(过滤器独立可替换)
- 可扩展性强(新增过滤器插入管道即可)
- 缺点:
- 不适合交互式系统(流式处理 vs 交互式)
- 空间效率低(数据需要在管道间拷贝),时间也受影响
这是数据流分解(data flow decomposition),按数据转换步骤切分,适合批处理系统。
1.4 四种架构横向对比
| 评估维度 | 共享数据 | 抽象数据类型 | 隐式调用 | 管道过滤器 |
|---|---|---|---|---|
| 算法变更适应性 | ++ | ++ | + | + |
| 数据表示变更适应性 | - | ++ | + | + |
| 功能增强适应性 | - | - | ++ | + |
| 性能 | ++ | + | - | - |
| 复用性 | - | + | ++ | ++ |
核心洞见:没有”最好”的架构,只有最适合当前变化场景的架构。架构设计的本质是对变化的权衡——预测哪些变化最可能发生,选择能最小化该类变化成本的分解策略。
二、Case Study 2:(页面空白,内容待确认)
笔记提取自 PDF 文本层,Case Study 2 部分仅有标题无正文内容,可能为纯图形幻灯片或未覆盖。待确认。
三、Case Study 3:机器人控制系统
3.1 四种架构方案
方案一:控制环(Control Loop)
- 结构:Controller 作为主动组件,通过传感器感知环境,通过执行器作用于环境
- 典型的闭环反馈控制架构
- 适用于简单、实时性要求高的机器人控制
方案二:分层架构(Layered Architecture)
从下到上的层次(感知→行动逐步抽象):
- 传感器解释层(Sensor interpretation)
- 传感器集成层(Sensor integration)
- 真实世界建模层(Real-world modeling)
- 导航层(Navigation)
- 控制层(Control)
- 全局规划层(Global planning)
- 监督层(Supervisor / 顶层决策)
- 每一层建立在下层抽象之上,向上层提供更高级的服务
- 典型的层次式分解,与操作系统/网络协议栈的分层思想一致
方案三:隐式调用(Implicit Invocation)
- 多个 Task 并行运行,通过消息派发(Message dispatched)通信
- 异常(Exception)和 Wiretap(监听)机制
- 松耦合,适合多任务并发的机器人系统
方案四:黑板架构(Blackboard Architecture)
- Blackboard(黑板)作为共享知识区
- 各专家模块独立工作:Captain(船长/决策)/ Map navigator(地图导航)/ Pilot(领航)/ Lookout(瞭望/感知)
- 感知子系统向黑板写入数据,各专家从黑板读取并写入结果
- 典型的机会主义问题求解架构,适合多领域知识协作的复杂系统
四、Case Study 4:巡航控制系统(Cruise Control)
4.1 问题定义
巡航控制系统的目标:在变化的地形条件下,保持汽车速度恒定。
输入:
- 系统开/关(System on/off)
- 引擎开/关(Engine on/off)
- 车轮脉冲信号(Pulses from wheel,测速)
- 油门(Accelerator)
- 刹车(Brake)
- 增加/减少速度(Increase/decrease speed)
- 恢复速度(Resume speed)
- 时钟信号(Clock)
输出:
- 节气门控制(Throttle)
4.2 两种设计视角对比
视角一:对象视图(Object View)
- 用面向对象方法分析:识别系统中的对象(汽车、引擎、速度传感器、巡航控制器等)及其关系
- 关注对象的属性、方法、继承、关联
- 适合结构建模,但容易忽略实时控制和性能问题
视角二:过程控制视图(Process-Control View)
- 用过程控制方法分析:将系统视为反馈控制系统
- 关注:传感器采样 → 控制算法 → 执行器输出 的闭环
- 直接考虑实时性、正确性、性能等关键质量属性
4.3 分析与讨论
架构与问题的对应关系
- 巡航控制属于实时嵌入式控制类问题
- 面向对象方法倾向于先建模结构,后期才考虑性能和实时性 → 可能遗漏关键设计决策
- 过程控制方法从一开始就聚焦于反馈环路、时序、正确性 → 更符合问题本质
方法论启示
| 维度 | 自顶向下方法(Top-down) | 过程控制方法 |
|---|---|---|
| 关注点 | 功能分解 | 反馈环路、控制算法 |
| 性能考虑 | 后期优化 | 早期纳入设计 |
| 正确性 | 功能正确性 | 控制正确性(稳定性、超调、稳态误差) |
| 系统修改 | 模块级修改 | 控制参数调节 |
控制策略演进(性能维度)
- 开关控制(On/Off control):最简单,只有开/关两种状态,超调大
- 比例控制(Proportional Control):输出与误差成正比,更平滑,但有稳态误差
- 比例+积分控制(Proportional plus reset / PI):加入积分消除稳态误差
4.4 核心结论
设计方法论的威力,很大程度上取决于它在恰当的时机将注意力集中在重要决策上的能力。
巡航控制案例表明:对于嵌入式实时控制类问题,基于过程控制的方法论比常见的面向对象方法论更能引出关键的高层设计决策。
巡航控制代表了一类问题:真实世界的过程由嵌入式软件控制。这类问题要求早期就考虑性能和正确性问题——如果用 OO 方法起步,这些问题可能被推迟到后期才暴露。
五、总结与启示
架构选型的核心原则
- 没有银弹:没有一种架构风格适合所有场景
- 以变化为导向:架构设计的核心是预判变化,选择能最小化变更成本的分解方式
- 问题域匹配:架构风格应与问题域的本质特征匹配
- 批处理数据转换 → 管道过滤器
- 多领域知识协作 → 黑板架构
- 实时控制系统 → 过程控制/分层架构
- 功能易变的交互式系统 → 隐式调用/事件驱动
- 数据抽象为核心 → 抽象数据类型/OO
- 方法论的选择影响决策质量:不同的设计方法学引导设计者关注不同的决策点,选择合适的方法论与设计本身同样重要