简介:这份PPT面向软件工程课程学习者与备考需求分析章节的学生,聚焦“面向数据流的分析方法”这一核心主题,帮助读者理解从现实世界到计算机世界的抽象映射过程。资源共1个文件,为单个ppt演示文稿,压缩包约1.41MB,内容以讲义幻灯片形式组织,便于课堂讲解与自学翻阅。目前已有223人学习下载。课件以小型图书馆管理系统为贯穿案例,完整演示需求分析的全过程:先调查现实环境获得当前系统物理模型,再抽取本质建立逻辑模型,进而分析当前系统与目标系统的差别,构建并细化目标系统逻辑模型,最后进行需求验证。内容涵盖抽象、模型、逻辑模型与物理模型、需求定义、功能性需求与非功能性需求、需求获取内容及性能、环境、界面等约束,并对比结构化开发方法与面向对象开发方法,梳理面向信息流向与面向信息内容两类建模思路。适合需要掌握需求分析建模步骤、理解数据流分析方法的读者对照学习。
1. 教育场景下的数据流分析:从一份课件标题说起
一份名为“教育赵良软件工程面向数据流的分析方法.ppt”的课件标题,背后指向的是一个在软件工程教学里被反复讲、却很少被讲透的硬核话题:面向数据流(Data Flow)的分析方法。很多同学第一次接触 DFD(数据流图)时觉得不过是画几个圆圈、箭头和方框,真到课程设计或毕业设计里要拿它去拆一个教务系统、题库系统、在线评测系统,就发现画出来的图要么层级混乱,要么数据字典对不上,要么被导师一句“你这个数据流不守恒”打回来重做。这篇笔记就围绕教育场景下怎么把面向数据流的分析方法真正落地讲清楚,适合正在做软件工程课程设计的学生、需要带学生做需求分析的老师,以及想把 DFD 用在真实项目前期建模的开发者。
2. 面向数据流分析方法到底在分析什么
2.1 数据流分析的三层对象:加工、数据流、数据存储
面向数据流的分析方法,核心不是“画图”,而是用一套结构化语言把系统的数据运动描述清楚。它关注三个基本对象:加工(Process,对数据做变换)、数据流(Data Flow,数据在系统里移动的路径)、数据存储(Data Store,数据静止存放的位置),再加上外部实体(External Entity,系统边界外的数据源或终点)。这四个元素构成了 DFD 的全部词汇表。
在教育场景里,一个典型的“学生提交作业”动作可以拆成:外部实体“学生”发出“作业文件”数据流,进入加工“作业提交处理”,该加工把文件写入数据存储“作业库”,同时产生“提交回执”数据流返回给学生。你看,一个动作就自然映射成了四个元素。分析的本质,是不断追问:这份数据从哪来、经过谁的手、变成什么、存到哪、最后给谁。
这里有个容易被忽略的点:数据流分析是分层的。顶层图(上下文图)只画一个加工代表整个系统,把外部实体和它们与系统的数据流标清楚;0 层图把系统拆成若干主要加工;再往下每个加工可以继续分解成 1 层、2 层图。分层不是炫技,而是控制复杂度——一张图上加工数量超过 7 个左右,人眼就很难追踪数据守恒了。
2.2 为什么教育类系统特别适合用 DFD 做前期建模
教育类系统有一个天然优势:业务流程相对稳定且边界清晰。选课、排课、成绩录入、作业提交、题库组卷、在线判题,这些流程的输入输出定义明确,数据流向不像电商促销那样随时变。这意味着用 DFD 做需求分析,返工成本低,画出来的图能直接指导后续的数据库表设计和接口划分。
另一个原因是教育系统里“角色”和“数据权限”高度耦合。学生只能看自己的成绩,教师能录入所授课程的成绩,教务能看全院数据。这种权限差异在 DFD 里可以通过“同一数据流在不同层级加工中的可见性”来表达,比单纯用文字描述需求要精确得多。我一般会建议做教务类课程设计的同学,先把 DFD 画到 1 层,再回头写用例,会发现用例的粒度自然就对齐了。
2.3 从课件标题到可执行方案:一份 DFD 建模的最小工作流
把一份课件标题变成能交差的建模成果,我通常走这条路径:先定系统边界和外部实体,再画顶层图,然后逐层分解到 1 层或 2 层,同步维护数据字典,最后做平衡性检查。这条路径的关键是数据字典和 DFD 同步写,而不是先画完图再补字典——后者几乎必然对不上。
下面用一个“在线作业提交与批改系统”的最小例子,把每一步落到可复现的操作上。这里不依赖任何特定建模工具,用纯文本加结构化描述就能完成,方便你直接抄到课程设计报告里。
第一步,定义外部实体和数据流清单。用一张表把边界定死:
| 外部实体 | 输入数据流(流向系统) | 输出数据流(系统流向它) |
|---|---|---|
| 学生 | 作业文件、提交请求 | 提交回执、批改结果 |
| 教师 | 批改意见、评分 | 待批作业列表 |
| 教务 | 课程名单 | 成绩汇总 |
第二步,画顶层图。顶层图只有一个加工“在线作业系统”,把上表的数据流全部连上。这一步不要偷懒省略,它是后面所有分解的基准。
第三步,分解到 0 层。把系统拆成“提交处理”“批改处理”“成绩汇总”三个加工,检查每个加工的输入输出是否和顶层图一致。
第四步,写数据字典。对每一条数据流给出组成,例如“作业文件 = 学号 + 课程号 + 文件名 + 文件内容 + 提交时间”。数据字典的写法有固定符号:=表示组成,+表示与,[ ]表示选择,{ }表示重复。这个符号体系是面向数据流分析的标准配套,写报告时用上会显得很规范。
第五步,做平衡性检查。父图里某条数据流,在子图里必须能找到对应的入口或出口,不能凭空消失或凭空出现。这是导师最常抓的点,也是 DFD 最容易翻车的地方。
3. 用 DFD 拆解一个教务选课模块:从顶层图到数据字典
3.1 顶层图与 0 层图的画法及平衡性检查
选课模块是教育系统里数据流最密集的部分之一,拿它练手性价比很高。顶层图里,外部实体是“学生”“教师”“教务”,加工只有一个“选课系统”。学生流向系统的是“选课请求”“退课请求”,系统流向学生的是“选课结果”“课表”;教师流向系统的是“课程容量设定”,系统流向教师的是“选课名单”;教务流向系统的是“选课时间窗口”,系统流向教务的是“选课统计”。
0 层图把“选课系统”拆成四个加工:P1 身份与资格校验、P2 课程容量管理、P3 选课事务处理、P4 课表生成。数据存储有三个:D1 学生库、D2 课程库、D3 选课记录。
平衡性检查怎么做?拿“选课请求”这条流举例:顶层图里它从学生流向系统,那么在 0 层图里,它必须从学生流向P1(或直接流向某个加工),不能消失。再拿“选课结果”举例:顶层图里它从系统流向学生,0 层图里它必须从P3或P4流向学生。如果 0 层图里多出一条顶层图没有的数据流,比如“P2 直接向教师发送选课名单”,而顶层图里教师和系统之间只有“课程容量设定”和“选课名单”两条流,那这条新流要么补进顶层图,要么删掉——这就是平衡。
我见过太多课程设计在这一步被扣分:0 层图画得很热闹,回头一看顶层图还是最初那版,两边对不上。血泪经验是,每改一次子图,立刻回头改父图,别攒着。
3.2 数据字典的符号体系与四条编写规则
数据字典是 DFD 的“黑匣子”说明书,没有它,图上的箭头只是箭头。标准符号体系如下:
| 符号 | 含义 | 示例 |
|---|---|---|
= | 定义为 | 选课请求 = 学号 + 课程号 + 请求时间 |
+ | 与 | 学号 + 课程号 |
[ | ] | 选择 | 选课结果 = [选课成功 | 选课失败] |
{ } | 重复 | 课表 = {课程条目} |
( ) | 可选 | 选课请求 = 学号 + 课程号 + (备注) |
四条编写规则:第一,数据字典里的每个数据项必须能在 DFD 上找到对应数据流,不能有孤儿条目;第二,自顶向下逐层展开,顶层数据流先定义,再展开到字段级;第三,避免循环定义,A 由 B 组成、B 又由 A 组成是典型错误;第四,字段级定义要落到具体类型和长度,比如“学号 = 10 位数字字符串”,这样后面建数据库时可以直接用。
3.3 用 Python 做一次数据流一致性校验
手工检查平衡性容易漏,写个小脚本把 DFD 的节点和边读进来做校验,既快又能写进报告当亮点。下面这段代码用字典描述父子图的流集合,检查子图是否覆盖父图的所有流。
# DFD 平衡性校验:检查子图数据流是否覆盖父图 # 父图:加工 P0 的输入输出流 parent_flows = { "in": {"选课请求", "退课请求", "课程容量设定", "选课时间窗口"}, "out": {"选课结果", "课表", "选课名单", "选课统计"} } # 子图:0 层各加工的输入输出流汇总 child_flows = { "in": {"选课请求", "退课请求", "课程容量设定", "选课时间窗口"}, "out": {"选课结果", "课表", "选课名单", "选课统计", "内部日志"} } def check_balance(parent, child): missing_in = parent["in"] - child["in"] # 父图有、子图没有 -> 丢失 extra_in = child["in"] - parent["in"] # 子图有、父图没有 -> 凭空出现 missing_out = parent["out"] - child["out"] extra_out = child["out"] - parent["out"] return missing_in, extra_in, missing_out, extra_out mi, ei, mo, eo = check_balance(parent_flows, child_flows) print("子图缺失的输入流:", mi) print("子图多出的输入流:", ei) print("子图缺失的输出流:", mo) print("子图多出的输出流:", eo)这段代码的逻辑很直白:用集合差集找出父子图之间的不一致。参数说明上,parent_flows和child_flows分别代表父图和子图的数据流集合,实际使用时可以从建模工具导出的 XML 或自己维护的表格里读取。运行结果会告诉你“内部日志”是子图多出来的流——它要么补进父图(如果它确实跨越了系统边界),要么改成系统内部流不画在顶层图。这个脚本我一般会在 1 层图分解完后再跑一遍,比人眼靠谱。
4. 避坑:DFD 建模里最容易翻车的五个地方
4.1 坑一:把控制流当数据流画
现象:图上出现“点击提交按钮”“触发定时任务”这类箭头。原因:混淆了数据流和控制流,DFD 只描述数据运动,不描述执行顺序和触发条件。解决:把控制信息改写成数据流,比如“点击提交按钮”改成“提交请求”数据流;触发条件写在加工说明里,不画在图上。
4.2 坑二:加工只有输入没有输出,或只有输出没有输入
现象:某个加工像黑洞一样只进不出,或者像泉眼一样只出不进。原因:分解时漏掉了回执、日志或查询结果。解决:每个加工至少一进一出,这是 DFD 的基本守恒律。如果确实是纯查询加工,那输入是查询条件、输出是查询结果,仍然成立。
4.3 坑三:数据存储与外部实体直接相连
现象:一条箭头从外部实体直接指向数据存储,中间没有加工。原因:图省事,觉得“学生直接查数据库”很自然。解决:任何跨边界的数据访问都必须经过加工,因为加工才代表系统对数据的处理逻辑。正确画法是外部实体→加工→数据存储。
4.4 坑四:父子图数据流名字不一致
现象:父图叫“选课请求”,子图叫“选课申请”,导师一看就皱眉。原因:多人协作或多次修改后没有统一命名。解决:维护一份数据流命名表,所有图共用;改名时全局替换。这个坑看似小,但在评审时非常扎眼。
4.5 坑五:分解层数过深导致图失控
现象:为了显得详细,一路分解到 4 层,每层七八个加工,最后自己都说不清数据从哪来。原因:把 DFD 当流程图用,追求步骤完整。解决:DFD 分解到能说清主要数据变换即可,一般 1 到 2 层足够。再细的粒度交给数据字典和加工说明(结构化语言或判定表)去表达。
5. 把 DFD 用出进阶价值:从建模到验证的两个技巧
第一个技巧是用数据字典反推数据库表。DFD 里的数据存储,天然对应数据库的表;数据流里的数据项,对应字段。把数据字典整理成字段清单后,建表语句几乎可以自动生成。比如“选课记录 = 学号 + 课程号 + 选课时间 + 状态”,直接映射成一张选课表,主键是学号加课程号。这样做的好处是表结构有需求依据,不是拍脑袋定的。我一般会在数据字典定稿后,用一段脚本把条目转成 SQL 建表语句的草稿,再手工调整索引和约束。
第二个技巧是用加工说明做逻辑验证。DFD 只说了“做什么变换”,没说“怎么变换”。对每个底层加工写一段结构化说明,用顺序、选择、循环三种结构描述处理逻辑,然后拿它和 DFD 对照:说明里用到的数据项,图上必须有对应数据流;图上有的数据流,说明里必须被使用。这个交叉验证能抓出大量遗漏。比如“P3 选课事务处理”的说明里如果写了“检查先修课”,但图上没有“先修课信息”这条输入流,那就说明图漏了。
最后一个习惯:每次改完图,把顶层图、0 层图、数据字典三份东西并排打开,逐条流对一遍。这个动作花不了十分钟,但能省下返工一整天。面向数据流的分析方法不难,难的是耐心和一致性。希望帮到你。
本文还有配套的精品资源,点击获取