资讯动态

面向对象分析OOA:三大模型构建方法与常见建模陷阱详解

发布时间:2026/10/9 8:27:57 来源:尧图企业网站定制
记得标好图号先画哪个后画哪个心里要有数——这是每年软工课第九讲作业里最常见的翻车现场。第一周还能靠直觉画用例图第二周开始画类图就把自己绕进去了等到时序图一出来整个模型东一块西一块文档改了三四版依然是散的。之所以会这样本质上是对面向对象分析这几个字的理解停留在画图层面而不是把它当成一套从需求到模型的思维方式。这篇整理就是把计科/软工第九讲的内容从头捋一遍把OOA为什么存在、三大模型怎么串起来、每一步踩过的坑和对应的解决思路都讲清楚适合正在上课被作业逼着的同学也适合准备软工考试临时抱佛脚的考生以及刚接触需求分析的初级从业者。1. 第九讲到底在讲什么OOA的位置与价值面向对象分析英文叫Object-Oriented Analysis缩写OOA。放在软件工程的标准流程里看它处在需求获取与详细设计之间前一步是需求分析后一步是面向对象设计OOD。很多同学在这个节点容易晕就是因为分不清分析和设计的边界到底在哪。一个相对通行的划分标准是分析阶段回答的是系统该做什么设计阶段回答的是系统怎么做。听起来简单实际做题时边界会变得非常模糊。举个最典型的例子在分析阶段要不要定义类的属性类型要不要确定方法的具体实现算法答案是都不要。属性类型属于实现约束算法属于设计决策。分析阶段只需要识别出这个类有哪些属性、哪些职责至于属性是String还是int、方法是用冒泡排序还是快排那都是后面设计阶段的事。你一旦在OOA阶段开始考虑数据库表怎么建、界面怎么布局、消息队列怎么接就会陷入无穷无尽的技术细节把分析模型做成了设计模型最后两头不讨好。从整个项目周期来看OOA做得好不好直接决定后续OOD和编码的工作量。分析阶段把对象认漏了设计阶段就抓瞎关联关系画错了数据库建模和类实现全部跟着错。有经验的团队宁可花两个星期把分析做实也不愿在编码阶段返工三周。这就像盖房子图纸上画错了一根承重墙施工队干到一半才被发现拆掉重来的成本远大于当初多画一版图纸的成本。OOA的产出物是一套UML模型核心包括三种用例模型Use Case Model、领域模型Domain Model也常称为分析类模型、交互模型Interaction Model。这三种模型分别从功能视角、静态结构视角、动态协作视角描述系统三者合在一起才构成一个完整的分析结果。很多人只盯着某一幅图猛画比如一个用例图画得巨细无比类图和时序图却草草了事这就是对OOA的整体架构缺少认识。这一讲把所有概念串起来的逻辑可以这样理解先搞清楚系统外面有谁参与者这些人要系统做什么用例然后根据用例去推系统内部有哪些概念及关系候选类、类图最后沿着每个用例走一遍看看这些类是怎么协作的时序图。从这个顺序就能看出来三种模型不是并行的三个产物而是有先后依赖的推理链条。弄丢了其中一环整个分析链条就断了。到了课程后面的实验课和课程设计你会发现所有面向对象建模都要按这个框架走。哪怕不用UML工具手画草图思路也是同一个。与其说第九讲教的是画图不如说它教的是从用户视角出发、以对象为中心的思维方式。2. 三大核心模型与它们之间的生成顺序很多教材在讲OOA时会用螺旋图或者四个层次来描述但真正落实到做项目最顺手的是以模型为中心的三步法。先建用例模型再建领域模型最后建交互模型顺序不能乱。之所以不能乱是因为每一步的输入恰好是前一步的输出。2.1 用例模型系统要为谁做什么用例模型回答的是系统最主要的功能边界问题。它是一个完全站在用户视角的模型不关心内部实现甚至可以说它根本不关心面向对象这件事即使是用面向过程的方法做开发用例模型照样能建。它由参与者Actor和用例Use Case组成最终画成用例图。参与者的判断有一套非常朴素的标准谁在与系统交互谁是系统外部但需要从系统获取价值的事或物要注意的是参与者不一定非得是人也可能是另一个系统、一个定时器、一台外部硬件设备。比如一个自动售货机系统购买者是人而供货管理员也是人但它们的操作权限和用例完全不同要区分成两个参与者和相应的用例组。用例的粒度问题通常是课堂作业的重灾区。一个用例应该对应一个完整的、可独立描述的用户目标而不是一个单一的操作步骤。比如登录在大多数系统里不应该单独立成一个用例因为登录一般不承载独立的用户价值它是完成其他用例的前置条件。反过来把管理图书这样一个大块直接做成用例颗粒度又太粗因为买书和借书的用户目标完全不同应该拆成借阅图书归还图书新书入库等多个用例。2.2 领域模型系统内有哪些概念对象及它们如何关联领域模型是OOA的骨架。它把系统中要处理的关键概念用类和类的关联关系表达出来形式就是我们熟悉的分析类图。这一步最核心的产物是对象/类、属性、关联和多重性。领域模型来源于对用例模型的内容做进一步分析当用户要求实现借阅图书这个用例时系统内部一定涉及图书读者借阅记录等概念。把这些概念抽象成类再把它们相互之间的关系画清楚领域模型的基本框架就出来了。判断一个候选对象要不要成为类有一条经验法则看它是否有独立的状态、独立的行为、以及是否需要在系统内被单独识别和跟踪。领域模型里最忌讳的是把数据库设计思维带进来。不要在这个阶段考虑主键外键不要考虑范式更不要考虑表结构。分析类图里的类与现实中的表、类属性与表中的字段之间没有一一对应关系。这一点非常反直觉因为很多同学已经学过数据库画着画着就不自觉地开始考虑这个关联字段放哪张表里。领域模型也需要对用例模型中识别出的多重性关系做精确判断。一个读者可以同时借阅几本书一本书可以被几个读者连续借用这些封闭性问题直接决定了关联线两端的1和*标在哪里。多重性画错了到设计阶段接线就是一笔糊涂账。2.3 交互模型具体用例在对象之间如何协作有了类图我们还是不知道一个功能具体是怎么跑起来的需要一个动态视角来描述参与者与对象、对象与对象之间的协作过程。交互模型承担的就是这个任务。交互模型的标准呈现方式有两种时序图Sequence Diagram和协作图Communication Diagram也叫通信图两者表达的信息等价只是侧重点不同。时序图强调时间顺序纵向看消息先后协作图强调对象间的结构关系能一眼看出对象之间的连接。课程作业里90%以上用时序图就够了因为老师更想看你是否清楚谁先调用谁、后调用谁。画交互模型最实在的价值是能够反过来检验前面领域模型的正确性。如果在画时序图时发现某个用例要调用的方法在之前的类图中没有对应的类来承接或者某个对象在被画进交互时才发现它根本不需要存在那就是分析漏了或冒了。这种反馈循环就是建模的意义——模型之间互相校正。这三种模型配套起来看功能边界有了、静态结构有了、动态行为也有了分析阶段的目标才算达成。3. 用例建模的实施细节从需求描述到高质量用例图用例建模是整个OOA里最容易上手、但也最容易被低估的一个环节。说它容易是因为用例图符号少参与者和椭圆谁都能画说它容易被低估是因为真正决定用例图质量的是每一个用例背后的用例描述文档。很多老师会把用例描述的分数占比放得很高因为只画一张用例图根本说明不了系统的行为逻辑。3.1 参与者的识别与命名识别参与者的过程中有几个高频误判点需要格外留意。第一个误判点是把在系统里建一个账户的角色当成参与者。比如一个管理员可能在系统里被建模成一个对象但作为参与者时我们要问的是是否有人以管理员的身份与系统交互。如果某个角色的操作只是另一个用例的一部分没有独立发起交互的能力那它就不是参与者而是用例内部处理的一个对象而已。第二个误判点是忽略了次要参与者。一个完整的软件系统往往会有主参与者Primary Actor和辅助参与者Supporting Actor。主参与者是发起用例、从用例中直接获益的对象辅助参与者在用例执行过程中提供服务。比如在线购书系统中顾客是主参与者支付网关是辅助参与者。只在用例图里画了顾客而把支付网关漏掉这个用例的分析就是不完整的。第三个误判点是参与者名称不统一。同一角色有人写读者有人写顾客还有人写用户在正式文档里必须收敛成统一的术语。建议在项目的术语表Glossary里定义所有角色名称用例图、类图、时序图中的命名全部引用同一个术语避免后期文档对不上。3.2 用例粒度从目标到活动的区间判断用例粒度是否合适最有效的方法是使用完整可交付价值测试这个用例执行完后是否有一个明确的参与者得到了一个完整可识别且可验证的结果如果答案是否定的那它很可能只是另一个用例的子功能或步骤。以网上选课系统为例把登录验证当作一个用例执行完之后学生并没有获得任何选课相关的成果可验证结果不成立所以登录验证更适合作为网上选课的前置条件。反过来把学生选课、改课、退课全部揉进一个课程管理用例又过粗了因为改课和退课对应的用户目标和业务流程有差异需要分别建模。开学时画用例图我犯过粒度失衡的毛病。一口气把找回密码更换头像这类低价值小功能也画成了一个又一个用例图面上一堆椭圆主次不分。后来带我的工程师给了一句话用例图是给干系人确认需求用的不是操作手册目录次要的、低价值的、支撑性的行为放到用例描述的扩展场景里就够了。3.3 用例描述的主干加扩展写法有了用例图之后每个用例必须配上描述文本通常采用两个基本结构主成功场景Main Success Scenario和扩展场景Extensions。主成功场景描述的是系统按预期执行、用例目标顺利达成时的步骤序列。扩展场景则描述条件分支、异常处理、失败回滚等情况。标准用例描述的要素包括用例名、参与者、前置条件、后置条件、主成功场景、扩展场景。其中后置条件很容易被新手漏掉但它很关键。后置条件描述用例成功结束后系统必须保证达到的状态写清楚后置条件后面写异常处理的回滚逻辑时就有了依据。以一个归还图书用例为例主成功场景可以写成读者向系统提交归还请求。系统读取图书信息和读者信息。系统校验借阅记录是否存在且逾期状态正常。系统更新图书状态为在馆。系统更新读者的借阅历史记录。系统向读者展示归还成功结果。对应的扩展场景可能包括步骤3中如果借阅记录不存在系统提示错误并终止如果存在逾期系统计算罚款金额并生成待支付清单。这些细节光靠画图永远画不出来但它们才是需求分析里真正的价值所在。有一份能读的用例描述后面的领域模型和交互模型才有据可依。我见过不少同学用例图画得挺像样一写用例描述就只写一句话用户成功借书后面整个建模链条全部崩掉因为没有足够的细节可以支撑你再往下推理。4. 领域模型建模识别类、属性与关联关系的判断方法领域模型的建立方法在经典OOA方法里最著名的是名词划圈法。做法很简单把需求文档和用例描述拿来把所有名词划出来逐个筛选哪些应该作为类哪些只能当属性哪些根本不用管。这个方法对新手很友好至少有东西可画不会对着空白页面发呆但它的缺点也明显机械地划名词会得到大量垃圾候选类筛选过程如果没有清晰标准照样懵。我自己的经验是对每个候选类问三个问题这个候选对象在系统内是否有需要单独维护的状态这个候选对象是否需要被唯一标识和检索这个候选对象是否和其他类存在需要建模的关联三个问题只要有一个是肯定的这个候选类就值得保留。如果三个全部是否那它要么应该降级为某个类的属性要么就是纯业务名词不进入模型。比如书名肯定是名词但系统不需要单独维护书名对象的状态也不需要按书名对象去检索它就应该降级为图书类的属性。而借阅记录具备独立状态借出时间、归还时间、是否逾期需要被唯一标识也和图书读者存在关联所以保留为类。4.1 属性与类的辨析信息归属的边界判断一个信息是应该作为属性还是独立类又一个很好用的标准叫字典依赖法如果这个信息需要查询或依赖一份外部字典才能确定可选项那它往往是独立类比如图书分类可能不是直接写死一个字符串在图书类里而是有单独的图书分类表如果这个信息只是描述性的、不可拆分的那就是属性比如图书名称。有一种复杂情况是多值属性。一个读者可以有多个联系电话那么在分析模型里电话作为属性的直觉就会遇到麻烦。一种做法是把联系方式单独建模成类另一种做法是在读者类上用多重性为0..*的属性标注。采用哪种取决于后续系统会不会对电话本身做独立操作。这里我不给唯一答案因为分析阶段保留一点弹性是允许的你只要在文档里写清楚选择理由即可。4.2 关联、聚合与组合多重性之外的理解关联关系是类之间最普遍的关系表示两类实例之间存在某种语义连接。特别是多重性即关联两端各有多少实例参与这是必须写清楚的。多重性的常见值包括1、0..1、、1..、0..*不同取值在不同的业务规则下含义不同。拿读者-借阅记录举例一个读者可以有零到多条借阅记录所以读者端读法应该是借阅记录这一侧的多重性为0..*表示一个读者对应多条借阅记录而一条借阅记录必须有且仅有一个对应的读者所以读者那一侧的多重性是1。画关联线时多重性标注的位置和读法方向非常容易搞反每次画完要把图倒过来读一遍才能发现错误。聚合Aggregation和组合Composition是两类特殊的关联都表示整体与部分的关系但语义强度不同。聚合是弱拥有菱形画在整体侧表示部分可以脱离整体而存在比如社团-成员成员退出社团后依然存在。组合是强拥有菱形是实心的表示部分的生命周期由整体管理比如订单-订单项订单被删除订单项也就没有意义了。考试和作业里这两个符号的区别是必考点但实践中它们的适用场景比想象中模糊判断的核心还是生命周期从属关系。4.3 一个完整的类图推导示例用一个经典到不能再经典的例子串一遍客户-订单-商品建模。需求描述一个客户可以下多个订单一个订单包含多个订单项一个订单项对应一种商品包含购买数量和小计金额每个订单有订单编号、下单日期和总金额每个商品有商品编号、名称和单价。分析推理链客户和订单一个客户对应0..*订单一个订单只属于一个客户普通关联无强生命周期约束画普通实线。订单和订单项一个订单对应1..*订单项订单项离开订单无独立存在意义生命周期由订单管理使用组合关系实心菱形在订单一侧。订单项和商品一个订单项对应的商品可以是多个订单共享的商品与订单项之间为普通关联多重性为1对0..*。然后检查属性归属总金额是订单的属性而不是单独计算的函数分析阶段可以先把总金额作为派生属性处理是否在模型中显式标注取决于团队约定。单价是商品的属性而小计金额则是订单项的计算结果——合理因为订单项必须记录下单时刻双方的约定金额而不能实时查询商品当前单价。这就是一个干净的类图模型的推导过程。整个过程不掺数据库主外键不动实现算法只把概念和关系说清楚就好。5. 交互建模时序图的画法、顺序推导与常见错误时序图是动态模型里最常用的表达工具。它把参与者的生命线横向排布纵向按时间顺序排列消息。画好一张时序图不难难的是消息序列的推导过程要有据可依不能凭感觉瞎编。5.1 时序图的基本骨架与元素时序图的构成元素集中不同元素含义完全不同必须严格区分。看这张梳理表就能把符号认全元素画法含义生命线顶部矩形向下虚线表示参与者或对象在交互中存在的时间段激活条生命线上的细长矩形表示对象正在执行操作的时间段消息带箭头的水平实线箭头指向接收方表示一个对象调用另一个对象的方法或发送信号返回消息虚线箭头通常从左往右表示方法调用返回结果自调用从同一生命线出发又回到自身的粗箭头表示对象执行自身内部方法创建消息指向被创建对象顶部生命线框的带类型消息表示创建新对象销毁消息从调用方指向接收方、末端带有X标记的消息表示对象生命周期结束5.2 从用例描述推导消息序列的实操步骤画时序图之前必不可少的准备工作是先找到参与该用例的类对象。这些对象一般来自领域模型类图用例本身就会涉及用例描述的参与者、领域模型中的类等。比如归还图书用例涉及的类对象可以确定为读者归还控制类借阅记录图书这个控制类可以在类图中没有突出显示但交互建模时往往需要引入一个控制类对象来协调整个流程。然后把用例描述的主成功场景逐条翻译成消息序列。翻译规则是一句话描述了一个系统动作就对应一条或多条消息主语是谁消息的接收者就是谁动作类型是系统更新““系统校验”的时候一般意味着这个动作归属某个对象的职责。翻译完成后依次画在生命线之间。注意消息的顺序编号要与用例描述步骤顺序严格一致。用例描述里系统向读者展示归还成功结果对应一条返回消息或一个界面展示消息。每一步都不要漏。画完主成功场景以后再画扩展场景。扩展场景对应的序列一般画在另一张时序图里或者在原图中从分支点画分支推荐前者因为图面能保持清晰。处理扩展场景时要额外判断两个问题异常由哪个对象检测错误提示由哪个对象负责输出。这两个问题的分析依据依然是领域模型中的职责划分。5.3 时序图分析能暴露哪些模型错误时序图完成后反过来与之前的静态模型对照检查是收益最大的步骤。典型的第一类错误是某个对象在时序图里收到了消息但在类图里这个类根本没有对应的方法职责。比如时序图里图书类收到校验借阅资格的消息但类图里图书类的职责列表里没有记录这个方法这就是职责缺失需要回类图补全。第二类错误是时序图里创建了某些临时对象但类图里没有对应的类。这通常是分析漏类说明领域模型不完整。第三类错误则相反某个用例从头到尾都没用上领域模型里的某个类那就需要想清楚是这个类根本不是系统的关注点还是案例的路径设计有问题。时序图暴露的问题越多越说明它值得画这一层诊断价值没法从别的图上拿到。很多组在作业里把时序图画成了想当然的调用过程没有用例描述做输入结果就是消息序列与需求文档冲突。只要把用例描述→消息序列这个推导路径摆到桌面上冲突就会立刻暴露。5.4 状态图与活动图的处理原则有些教材还会把状态图和活动图并入OOA的交互模型。状态图描述单个对象在生命周期内的状态迁移适合表达状态较多的对象典型例子是订单对象的状态待支付、已支付、已发货、已完成、已取消。活动图描述一个业务流程中步骤之间的流转和分支更接近流程图的语义。课程作业中状态图不是必须画遍所有类只挑有明显状态变化和复杂转移条件的类来画即可。活动图一般来说不属于OOA的强制产出物但在涉及多分支流程时活动图对描述用例主场景也非常有效。你要是时间紧可以只画一个状态图放到订单或借阅记录这类生命周期明显的类上其余类不必强行画状态图。6. 合格分析模型的自查清单与实战经验分析模型画完了判断自己画得好不好需要一个客观标准。考试和项目验收都不会只看图多不多而是看模型是否做到了完整、一致、清晰三件事。6.1 三份检查列表完整性检查指的是用例模型覆盖了所有功能需求领域模型能支撑所有用例的目标交互模型能讲清每个用例如何由对象协作完成。最容易缺的是辅助参与者、扩展场景和交互模型对异常流程的描述。一致性检查更具体。术语不一致最常见一个对象在用例描述里叫读者在类图里叫用户在时序图里叫顾客这种低级失误会直接拉低文档质量。其次是多重型转义错误用例描述里每本书只能借给一个人与类图里的多重性1对*不一致。把三个模型的图互相叠起来检查一遍自然能找出大量不一致问题。清晰性检查偏主观一些基本原则是让一个完全没接触过本项目的人拿过文档就能读懂模型。表达方法是用例名和类名都用完整的领域术语不用缩写每个用例必须附带描述文本类图里的关联线上除了多重性之外尽量补上关联名比如提交包含等。关联名看着只是多写了两个字但能大幅降低图面的阅读难度。6.2 OOA与OOD混淆的典型实证课上老师反复强调OOA和OOD要分开但大家还是会不断越界。常见的越界形式有这么几种一是要求类里的操作必须匹配某个具体的技术框架比如必须定义serialize方法这明显是设计甚至实现层面的约束。二是在类图上画出界面类和数据访问类这是绝大多数小组项目最容易出现的违规操作。分析阶段的类图应该只包含业务概念类界面、数据库、通信框架一概不出现。如果你在分析类图里看到了类似LoginPanel、DBHelper的名字那就得停下来想一想了。三是把数据库表的主外键关系画成关联比如给订单类加一个字段名叫customerId还把这个字段作为关联标注写上去。分析类图里类与类之间是直接的语义关联不需要通过ID间接引用引入ID和引用是设计阶段数据库设计的习惯性动作。6.3 做项目比考试更容易犯的隐性错误考试题通常会给一个较短的场景描述根据描述去建模关键信息都在题面上。但做课程设计或小组项目时需求是零散的没有人帮你把关键对象圈出来这时候分析工作的重心要从画图转移到需求挖掘。我自己带过的小组里返工最频繁的原因集中在两点一是初始需求描述里没有暴露某些对象状态和规则导致领域模型完整度不足二是大家跨过了分析阶段直接画设计类图把设计结果当分析成果交上去老师一答辩就露馅。应对方案是做一个前期的需求梳理表把需求来源、对象、规则逐条整理出来。比如需求原文涉及对象关键规则/约束所属用例每位读者最多同时借阅5本书读者、借阅记录、图书读者有效借阅数量不超过5借阅图书逾期还书按天计算罚款借阅记录逾期单价与计算规则待产品确认归还图书把这样的表填完再去建模型比你对着空气冥思苦想效率高得多。这也是为什么我反复强调用例描述是源头素材因为你做后续分析的全部依据都是用例描述和需求梳理表里稳定沉淀出的信息。6.4 关于工具选择的个人建议不管是什么工具重要的是图能快速改、快速迭代。早期阶段用纸笔或白板画草图完全可行但进入作业提交阶段还是用正式工具比较稳妥。绘图工具的选择标准就三条支持UML规范符号、支持元素间连线自动吸附、方便导出图片或PDF。我自己用PlantUML比较多因为它能用文本定义图改起来非常快一个类图调整关联线或属性只需要改一行描述然后重新生成。举个例子一张简单的时序图画起来不会超过5分钟startuml actor 读者 读者 - 归还控制类 : 提交归还请求 归还控制类 - 借阅记录 : 查询借阅记录 归还控制类 - 图书 : 更新图书状态 读者 - 归还控制类 : 展示归还结果 enduml不过用文本画图对初学者不友好因为看不到即时反馈容易因为紫语法报错而劝退。第一次做建模作业的时候我建议还是先用手边的可视化UML工具比如StarUML或Draw.io把概念理顺等到你对类图元素以及多重性有把握了再尝试PlantUML这类文本画图方式效率会明显提升。最后再多说一句分析阶段的产物不是一次性永恒的需求变了模型就要改而且改动必须沿着用例模型→领域模型→交互模型这条链路顺序传导不能只偷偷改一张图。保持模型三者同步是后续设计阶段最省钱的做法。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑