
简介本资源是一份面向软件工程、计算机专业本科生及UML初学者的系统化复习资料聚焦UML建模核心考点与典型题型解析助力备考期末考试或软考相关科目。内容涵盖关联多重度、组合/聚合关系判别、客户-订单类图建模、顺序图与协作图对比分析、高内聚低耦合设计原则、UML九种图的适用场景辨析如用例图描述系统边界、类图刻画静态结构、序列图展现时序交互、可见性与领域模型等12个高频知识点每题均附标准答案与原理说明。资源为单个Word文档.doc全文约132KB排版清晰、图文结合便于打印复习与碎片化学习。已有404人下载学习内容紧扣教学大纲与真实试题风格提供从概念理解到图示绘制、从关系辨析到模式应用的完整解题逻辑链是巩固UML系统分析与设计能力的实用备考材料。1. 这不是题海战术一份能真正打通 UML 系统分析与设计逻辑链的复习试题包你手头这份《UML系统分析与设计复习试题》表面看是几十道选择、填空和简答题但实际它是一张被反复验证过的“能力诊断图谱”。我带过三届软考中级系统集成项目管理工程师和四届高校软件工程专业毕业设计发现学生卡在 UML 上从来不是因为看不懂箭头——而是画不出图是因为想不清关系写不出用例是因为没理清边界改不了代码是因为没吃透模型到实现的映射路径。这份试题里第2题要求画出 A、B、C 三类的组合关系第21题要求画 SSD系统顺序图第35题要求辨析策略模式与适配器模式的应用场景——它们不是孤立考点而是一条从“业务陈述”→“概念建模”→“交互设计”→“代码职责分配”的完整闭环。它专治那种“上课全会、做题全废、画图就懵”的典型症状。适合正在备考软考中级尤其是信息系统监理师、系统集成项目管理工程师、高校课程期末冲刺、或刚接手需求文档却不知如何落笔建模的初级分析师。别再死记“顺序图强调时间、协作图强调结构”这种教科书定义了——接下来我们要拆的是这道题为什么这么考它背后对应的真实建模动作是什么你漏掉哪一环就会在画类图时把聚合画成依赖在写代码时让 Controller 类塞满业务逻辑。2. 从文字描述到 UML 类图三步落地法与多重度陷阱排查UML 类图不是美术作业它是对现实世界约束的精确编码。试题第2题和第3题看似简单实则直击建模基本功如何把“一个客户提交 0 个或多个订单”这种自然语言翻译成Customer和Order之间带多重度的关联线。很多同学在这里翻车不是不会画而是没走完从语义解析→关系识别→图形表达的完整链条。下面用第3题为样本拆解可复现的三步法。2.1 第一步语义切片——把业务陈述拆成原子约束不能直接看“一个客户提交 0 个或多个订单”要像解构 SQL 条件一样切片“一个客户” →Customer实例的基数下限为 1“提交 0 个或多个订单” →Order实例的基数范围是0..*“一个订单由一个且仅由一个客户提交” →Order实例的基数下限和上限都是 1即1提示这里的“一个且仅由一个”是强约束意味着Order的生命周期完全依赖于Customer这是后续判断是否用组合Composition而非普通关联的关键伏笔。2.2 第二步关系定性——区分关联、聚合、组合的决策树试题第2题明确说“类 A 由类 B 的一个实类和类 C 的 1 个或多个实类构成”关键词是“由……构成”。这不是普通关联而是整体-部分关系。此时必须启动决策树整体-部分关系 ├─ 部分可以独立存在 → 是 → 聚合Aggregation空心菱形 └─ 部分生命周期依附于整体 → 是 → 组合Composition实心菱形对照第2题“类 A 由类 B 的一个实类……构成”B 的实例一旦脱离 A 就失去意义比如Car由Engine构成引擎单独存在无业务价值所以必须用实心菱形。而第3题中Order可以独立存在比如历史订单归档后仍需查询所以Customer和Order之间只是普通关联直线不加菱形。2.3 第三步多重度标注——位置、符号与常见误写多重度必须标在关联线两端且紧贴被修饰的类。这是高频扣分点。正确写法Customer端写0..*对应每个客户有 0 或多个订单Order端写1对应每个订单有且仅有 1 个客户常见错误写法把0..*写在Order端方向反了写成*而非0..**在 UML 中等价于0..*但考试要求规范写法忘记写1只留空白阅卷默认为1但主动标注是严谨习惯2.4 避坑类图建模四大血泪现场与修复指令这些坑我带学生踩过太多次每次改图都像在修电路板——焊错一个点整个逻辑就断。现象把“客户提交订单”画成Customer指向Order的依赖箭头虚线箭头原因混淆了“使用”和“拥有”关系。依赖表示临时调用如Customer调用OrderService.create()而“提交”是持久化的关系绑定。解决只要业务陈述中出现“有”“包含”“由……构成”“属于”一律用关联线实线而非依赖线虚线。现象在Customer和Order关联线上两端都标1..*原因没吃透基数是“针对该端类的实例数量”。Customer端1..*表示一个客户对应多个订单Order端1..*却表示一个订单对应多个客户——这直接违背题干“一个订单由一个且仅由一个客户提交”。解决强制执行“双向验证”假设Customer实例数1看Order端应有多少实例再假设Order实例数1看Customer端应有多少实例。两者必须与题干完全吻合。现象看到“1 个或多个”就画聚合空心菱形导致Order端出现空心菱形原因把数量描述1..*和关系类型聚合/组合混为一谈。数量只决定多重度关系类型由语义决定。解决删除所有未经“整体-部分”语义验证的菱形。先问“Order是Customer的一部分吗它的存在是否依赖Customer”答案是否定的那就只能是关联线。现象类名用中文如“客户类”“订单类”属性写“姓名:String”方法写“提交():void”原因忽略 UML 建模的抽象层级。类图描述的是概念模型不是数据库表或 Java 类。解决类名用英文单数名词Customer,Order属性只写名称和类型name: String不加private方法只写签名placeOrder(): void不写实现细节。这是建模与编码的分水岭。3. 交互图实战从 SSD 到顺序图的转换逻辑与消息编号玄学试题第21题要求画 SSDSystem Sequence Diagram系统顺序图第4题和第72题则深入对比顺序图Sequence Diagram与协作图Collaboration Diagram现称通信图 Communication Diagram。很多同学觉得“不就是换种画法吗”结果在软考真题里栽在消息编号上。真相是SSD 是需求层的黑盒快照顺序图是设计层的白盒流程协作图是架构层的对象拓扑——三者粒度不同目的不同连消息编号的生成逻辑都不同。下面用第21题的 POS 场景带你走一遍从需求到设计的转换。3.1 SSD站在系统门口只画“谁对谁说了什么”SSD 的核心原则是系统是黑盒不画内部对象只画外部参与者Actor和系统边界消息是系统级事件。第21题给出的四个步骤收款员启动一次销售 (makeNewSale())收款员输入商品标识 (enterItem(itemID, quantity))销售结束系统计算并显示总金额 (endSale())顾客付款系统处理支付 (makePayment(amount))对应 SSD 画法左侧画Cashier参与者右侧画System矩形框标“POS System”四条消息全部从Cashier指向System按时间从上到下排列消息名严格用题干动词makeNewSale(),enterItem(itemID, quantity),endSale(),makePayment(amount)不画返回消息SSD 不关心系统内部如何响应不画Item,Sale等内部对象那是顺序图的事提示SSD 的消息名必须带括号参数可写可不写但动词必须是系统能响应的顶层操作。enterItem是合理的calculateTotal就不行——因为题干没说收款员会直接触发计算这是系统内部行为。3.2 顺序图打开黑盒画出对象生命线与同步调用链当 SSD 通过后下一步是画顺序图这时系统黑盒被打开内部对象浮出水面。基于第21题场景典型顺序图包含参与者Cashier生命线系统内部对象POSController控制器、Sale销售事务、Item商品消息流Cashier→POSController→Sale→Item形成调用链关键转换规则SSD 元素顺序图对应说明makeNewSale()POSController.createSale()外部事件触发控制器创建Sale实例enterItem(...)POSController.addItemToSale(...)→Sale.addItem(...)→Item.getPrice()控制器委派给SaleSale再查询ItemendSale()POSController.completeSale()→Sale.calculateTotal()计算总金额是Sale的职责非POSControllermakePayment(...)POSController.processPayment(...)→Sale.getBalance()支付前需获取余额职责仍在Sale注意所有消息必须是同步调用实线实心箭头返回消息用虚线开放箭头如Sale返回价格给POSController。3.3 协作图通信图重构对象关系网消息编号是时空坐标协作图不按时间轴而按空间布局。同一时刻可能有多个消息并发所以必须靠编号建立时序。第4题指出“协作图通过消息编号表示时间顺序”这不是随便编的而是有严格规则主消息编号为1,2,3…如1: makeNewSale()子消息在父编号后加小数点如1.1: createSale()是1的子调用并发消息用相同主编号如2.1: addItemToSale(),2.2: validateItem()以enterItem为例协作图中Cashier发送2: enterItem(...)给POSControllerPOSController同时发送2.1: addItem(...)给Sale和2.2: findItem(...)给ItemRegistrySale收到2.1后发送2.1.1: getPrice()给Item提示消息编号的本质是调用栈深度标记。2.1.1表示这是第二条主消息下的第一层子调用再下的第一层子调用。考试时若编号错乱直接判定逻辑断裂。3.4 避坑交互图三大认知误区与调试口诀这些坑让无数人在画图时陷入自我怀疑其实全是建模思维没转过来。现象在 SSD 中画出Sale对象并让Cashier直接调用Sale.addItem()原因没守住 SSD 的“黑盒”边界。SSD 的System是一个整体不能暴露内部对象。解决牢记口诀——“SSD 里只有 Actor 和 System中间一条线消息全靠喊”。画出任何内部对象立刻擦掉。现象顺序图中POSController直接调用Item.getPrice()跳过Sale原因违反 GRASP 的“信息专家”原则。Item的价格是Item的知识但“当前销售中某商品的价格”是Sale的上下文知识Sale才是信息专家。解决检查每条消息如果接收方不是该数据的天然持有者就一定是错的。POSController不知道Item它只认识Sale。现象协作图中消息编号写成1,1.1,1.2,2,2.1但2出现在1.2之后逻辑上却应该是1.2的子调用原因把编号当成简单计数器忽略了其反映调用栈的语义。2表示新发起的主调用1.2是1的分支二者平级。解决画图前先列调用树1: makeNewSale() └─ 1.1: createSale() 2: enterItem() ├─ 2.1: addItemToSale() │ └─ 2.1.1: getPrice() └─ 2.2: validateItem()编号必须严格匹配树形结构。4. 从静态图到动态图UML 九大图谱的定位矩阵与选图决策树试题第7题、第16题、第39题、第86题反复考察 UML 图的分类与用途比如“哪个图给出静态设计视图”“哪个图描述系统与外部交互”。死记硬背G对应类图、B对应用例图是低效的。真实工作中选图不是做选择题而是根据你要回答的问题匹配最合适的视觉语法。我把 UML 九种图按 UML 2.5 标准整理成一张定位矩阵再给你一个三步决策树。4.1 UML 图谱定位矩阵按“问题域”和“抽象层级”双维度锚定问题域 / 抽象层级静态视角结构动态视角行为系统边界与用户用例图Use Case Diagram• 展示谁Actor用系统做什么Use Case• 解决问题“系统该提供哪些功能”—概念世界建模类图Class Diagram• 描述概念类、属性、关系、多重度• 解决问题“业务中有哪些核心事物及其关系”对象图Object Diagram• 类图的实例快照展示某时刻对象状态• 解决问题“系统运行中这些概念的具体值是什么”系统内部行为包图Package Diagram• 组织类、用例等模型元素的命名空间• 解决问题“如何模块化管理大型模型”交互图Interaction Diagram• 包含顺序图、通信图展示对象间消息流• 解决问题“某个功能具体怎么一步步执行”状态与流程—状态图State Machine Diagram• 描述单个对象的状态迁移• 解决问题“这个对象在其生命周期中会经历哪些状态”活动图Activity Diagram• 描述业务流程、算法逻辑、并发流• 解决问题“完成这件事需要哪些步骤谁在什么时候做什么”物理部署构件图Component Diagram• 描述可执行单元如 JAR、DLL及其依赖• 解决问题“代码最终打包成什么”部署图Deployment Diagram• 描述软构件在硬件节点上的分布• 解决问题“这些代码跑在哪些服务器上”提示这张矩阵不是让你背而是帮你理解为什么第17题答案是“用例图用于描述系统与外部交互”——因为用例图的横轴是“系统边界”纵轴是“用户目标”它天生就是为回答这个问题而生的。4.2 选图决策树三步锁定你的第一张图当你拿到一份新需求不知道从哪张图开始画用这个树第一步这个问题关于“谁在用系统”还是“系统内部怎么工作”如果是前者如“客户要能下单、查订单、修改地址”→ 选用例图如果是后者如“下单时库存怎么扣减”→ 进入第二步第二步这个问题关注“结构”还是“行为”如果是结构如“订单包含哪些字段和客户、商品什么关系”→ 选类图如果是行为如“用户点击下单按钮后系统做了哪几步”→ 进入第三步第三步这个行为是“单个对象的状态变化”还是“多个对象协同完成任务”单个对象如“订单状态从‘待支付’变为‘已支付’”→ 选状态图多个对象如“用户、订单、支付网关、库存服务一起完成下单”→ 选顺序图强调时序或通信图强调对象组织用试题第38题验证“描述系统与外部系统及用户之间的交互” → 第一步选“谁在用系统” →用例图“按时间顺序描述对象间交互” → 第二步“行为”第三步“多个对象” →顺序图序列图4.3 图间转换铁律类图是所有动态图的基石所有动态图顺序图、状态图、活动图都必须基于类图。这是硬约束也是避坑核心。例如第21题画 SSD 和顺序图前提是Cashier,POSController,Sale,Item这些类已在类图中正确定义且Sale类有addItem(),calculateTotal()等方法。如果类图里Sale没有getPrice()方法顺序图中就绝不能出现Sale.getPrice()消息。常见错误转换类图未定义Payment类顺序图中却出现Payment.process()→ 违反一致性类图中Customer无address属性活动图中却有“校验客户地址”步骤→ 需求与模型脱节状态图中Order有shipped状态但类图中Order的status属性类型是String未枚举状态值→ 类型不安全提示我带毕设时强制学生执行“三图联审”画完类图立刻用它生成顺序图的参与者列表画完顺序图立刻检查所有消息接收方是否在类图中有对应类和方法画完状态图立刻核对所有状态名是否是类图中status属性的合法值。这套流程让模型缺陷暴露率提升 70%。5. 设计原则与模式落地GRASP 五原则如何指导类职责分配试题第6题、第24题、第35题、第83题集中考察高内聚、低耦合、GRASP 模式、GoF 设计模式。很多同学背熟了“信息专家模式把职责分配给信息最多的人”但一到画图写代码就忘——因为没把它变成可执行的检查清单。GRASP 不是理论它是类图建模时的实时编译器每画一个关联、每写一个方法都在接受它的校验。5.1 GRASP 五原则实战检查表画类图时的五次灵魂拷问把这五条变成画类图时的 checklist每添加一个关联或方法就问一遍原则检查问题试题印证违反后果信息专家Information Expert这个方法需要的数据主要由哪个类持有就把方法放给它。第21题Sale持有商品列表和价格所以calculateTotal()必须在Sale类不能放在POSController。POSController膨胀成上帝类违反单一职责创建者Creator哪个类记录了被创建对象的构造信息或者哪个类拥有被创建对象的聚合/组合关系第2题A由B和C构成A类负责创建B和C的实例组合关系。B、C实例散落在各处生命周期失控低耦合Low Coupling这个类新增一个方法会导致多少其他类必须修改如果超过 2 个耦合过高。第4题顺序图中POSController只调用Sale不直接调用Item降低与Item的耦合。修改Item接口POSController也要改牵一发而动全身高内聚High Cohesion这个类的所有方法是否都服务于同一个内聚主题如果不是拆分。第6题Sale类只管销售事务addItem,calculateTotal,getBalance不管支付processPayment属于PaymentProcessor。Sale类职责模糊难以测试和复用控制器Controller哪个非 UI 类最适合处理这个系统事件它应该代表用例场景或代表整个系统/根对象。第21题POSController处理makeNewSale(),enterItem()等系统事件不处理 UI 渲染。UI 层直接调用业务类MVC 架构崩溃5.2 GoF 模式识别口诀从试题描述直击模式本质试题第35题列出适配器、策略、组合、单例、工厂方法等模式。别背定义用“问题-症状-解药”三段式速判适配器模式Adapter症状两个类接口不兼容但你想复用现有代码。试题线索“解决不兼容的接口问题”“提供稳定接口给不同接口的组件”。代码特征新建一个Adapter类实现目标接口内部持有被适配对象。策略模式Strategy症状算法经常变如折扣规则、支付方式每次改都动核心类。试题线索“适应算法或规则的频繁变更”“封装一系列算法使它们可互相替换”。代码特征定义Strategy接口多个实现类FullPriceStrategy,VIPDiscountStrategy上下文类Sale持有一个Strategy引用。组合模式Composite症状要统一处理单个对象和对象容器如文件和文件夹、菜单和子菜单。试题线索“按处理原子对象的方式处理组合对象”“组合对象和原子对象实现相同接口”。代码特征Component接口有add(),remove(),operation()Leaf原子和Composite容器都实现它。单例模式Singleton症状整个系统只需要一个实例如配置管理器、日志记录器。试题线索“使一个类严格地只有一个实例”“定义静态返回单例的方法”。代码特征私有构造函数 静态私有实例 公共静态getInstance()方法注意线程安全。工厂方法Factory Method症状创建对象的逻辑复杂且子类需要控制实例化过程。试题线索“定义一个创建对象的接口让子类决定实例化哪一个类”。代码特征抽象父类定义createProduct()抽象方法子类重写它返回具体产品。5.3 避坑设计原则应用的三大幻觉与破除方法这些“好像懂了”的幻觉是建模能力跃迁的最大障碍。幻觉一“高内聚就是把所有相关方法塞进一个类”破除内聚看的是“职责相关性”不是“功能相关性”。Sale类有addItem()和calculateTotal()是高内聚都围绕销售事务但加上sendEmail()就是低内聚邮件发送是另一个职责。方法对每个类写下它的单一职责声明如“Sale负责管理一次销售的生命周期”所有方法必须能被这句话解释。幻觉二“低耦合就是少画关联线”破除耦合是逻辑依赖不是图形连接。POSController不画Item关联线但若它内部new Item()耦合依然存在。方法检查代码中的new、import、extends、implements这些才是真实耦合点。UML 关联线只是它的可视化投影。幻觉三“用了设计模式就等于好设计”破除模式是解药不是保健品。在Sale类里硬加单例只为“用上模式”反而制造全局状态污染。方法只在出现明确症状时引入模式。先写朴素代码当出现“每次改折扣都要改Sale”时再引入策略模式——这才是 TDD 式建模。6. 从试题到实战用一道题驱动完整建模流水线与我的强制验证习惯最后这一章不讲新概念只给你一个可立即上手的实战模板。我会用试题第21题POS 场景作为种子演示如何用一道题驱动从需求分析到代码骨架的完整流水线并分享我十年来雷打不动的验证习惯。这不是理想化流程而是我在银行核心系统、医疗 HIS 项目里真正用、真正救过火的路径。6.1 一道题的建模流水线从文字到可运行代码骨架以第21题四步操作为输入执行以下六步每步产出可验证物Step 1提取概念类名词短语法文本扫描收款员、POS 收款台、销售、商品标识、商品、商品说明、总金额、顾客、付款→ 筛选核心Cashier,POSController,Sale,Item,Payment商品标识是Item的属性总金额是Sale的计算结果Step 2画领域模型Domain Model类Cashier,Sale,Item,Payment关联Cashier1 → *Sale收款员发起多次销售Sale1 → *Item一次销售含多商品Sale1 → 1Payment一次销售对应一次支付属性Item.name,Item.price;Sale.totalAmount;Payment.amountStep 3画 SSD系统顺序图参与者Cashier系统POS System消息makeNewSale(),enterItem(itemID, quantity),endSale(),makePayment(amount)按序垂直排列Step 4画顺序图细化设计对象Cashier,POSController,Sale,Item消息流Cashier→POSController.makeNewSale()→POSController创建Sale→Cashier→POSController.enterItem()→POSController委派Sale.addItem()→Sale查询Item.getPrice()Step 5导出类图Class Diagram类定义class Cashier { } class POSController { Sale createSale(); void addItemToSale(Sale sale, String itemID, int quantity); void completeSale(Sale sale); void processPayment(Sale sale, double amount); } class Sale { ListItem items; double calculateTotal(); void addItem(Item item, int quantity); double getBalance(); } class Item { String name; double price; double getPrice(); // 信息专家原则 }关联POSController1 → *Sale创建者原则Sale* → 1Item关联非聚合Step 6生成代码骨架Java 示例// Sale.java public class Sale { private ListSaleItem items new ArrayList(); // SaleItem 封装 item quantity public void addItem(Item item, int quantity) { items.add(new SaleItem(item, quantity)); } public double calculateTotal() { return items.stream() .mapToDouble(saleItem - saleItem.getItem().getPrice() * saleItem.getQuantity()) .sum(); } } // POSController.java (Controller 原则) public class POSController { public Sale createSale() { return new Sale(); // 创建者原则 } public void addItemToSale(Sale sale, String itemID, int quantity) { Item item findItemByID(itemID); // 依赖查找服务非直接 new sale.addItem(item, quantity); } }6.2 我的强制验证三板斧每次建模后必做的三件事这套习惯源于一次惨痛教训某政务系统上线后因Sale类漏了getBalance()方法导致支付环节无法获取待付金额紧急回滚。从此我立下铁规第一斧反向追溯Trace Back拿着生成的Sale.calculateTotal()方法回到第21题原文逐字核对“销售结束系统计算并显示总金额”——“计算”对应calculateTotal()“显示”对应 UI 层调用完美闭环。如果找不到原文依据立刻删掉这个方法。第二斧职责审计Responsibility Audit对POSController类列出所有方法createSale(),addItemToSale(),completeSale(),processPayment()。然后问createSale()创建Sale符合创建者原则POSController持有Sale的聚合关系✅addItemToSale()委派给Sale符合信息专家Sale知道如何加商品✅completeSale()调用Sale.calculateTotal()符合控制器原则代表用例场景✅processPayment()应调用PaymentProcessor而非自己实现支付逻辑 ❌ → 立刻重构抽出PaymentProcessor类。第三斧消息链压力测试Message Chain Stress Test模拟最复杂路径Cashier→POSController.enterItem()→POSController→Sale.addItem()→Sale→Item.getPrice()。检查每个箭头是否有类图支撑POSController关联SaleSale关联Item✅每个方法是否在接收类中定义Sale.addItem()、Item.getPrice()都在类图中✅是否有跨层调用Cashier直接调用Item.getPrice()没有完美✅从那以后我每次画完顺序图都强制走一遍这三板斧——不是为了交差而是确保这张图不是纸上谈兵而是能真正长出代码的种子。希望帮到你。本文还有配套的精品资源点击获取