☰
UML建模三张地图:静态结构、动态行为与职责分配
2026/10/27 11:57:34 网站建设 项目流程

简介:本资源是面向软件工程专业学生及UML初学者的系统化复习资料,聚焦UML系统分析与设计核心考点,助力课程考试、软考中级系统设计师备考及建模能力夯实。内容涵盖关联多重度判定、组合关系识别、客户-订单业务建模、顺序图与协作图对比分析、高内聚设计原则、UML九种图的定位与选用(如类图表静态视图、用例图述系统边界、序列图显时序交互)、依赖/关联/泛化/实现四类关系辨析、领域模型构建等12个高频知识点,并附详细解析与标准答案。资源为单文件Word文档(.doc),全文约132KB,结构清晰、题型典型、解析透彻,便于打印精读或碎片化复习。已有405人学习下载,适合需要快速掌握UML建模逻辑、厘清易混淆概念、提升试题应答准确率的学习者。

1. UML系统分析与设计:一张不能只靠死记硬背的“建模地图”

如果你正在翻这本《UML系统分析与设计复习试题》,大概率不是为了学怎么画漂亮图,而是想搞懂:为什么同一个业务场景,有人画出的类图能直接指导编码,有人画完连自己都看不懂?为什么协作图和顺序图总被混用却扣分?为什么GRASP原则一提就懵,但面试官张口就问“谁该创建这个对象”?
梳理下来会发现,UML从来不是9种图的简单罗列,而是一套分层、有主次、强约束的建模语言体系——它把软件开发中“想清楚”这件事,拆解成三张不可替代的地图:
✅静态结构地图(类图/对象图/包图/构件图/部署图):回答“系统由哪些东西组成?它们之间怎么组织?”——这是代码骨架的蓝图;
✅动态行为地图(用例图/活动图/状态图/交互图):回答“系统在什么条件下做什么事?事情怎么一步步发生?”——这是业务逻辑的运行脚本;
✅职责分配地图(GRASP + 设计模式 + SSD契约):回答“谁该知道什么?谁该负责什么?变化来了往哪改?”——这是让代码不散架的底层协议。

这三张地图彼此咬合:用例图框定边界,领域模型提炼真实世界概念,SSD图锁定系统边界与事件流,类图定义静态结构,交互图验证动态协作,GRASP原则决定职责落点,设计模式解决高频变体。漏掉任何一层,建模就变成玄学——画得再标准,也经不起一次需求变更的推敲。
这份复习题集的价值,正在于它不孤立考图,而是用真题把这三张地图的接缝处全暴露出来:第3题客户与订单的多重度,表面考符号,实则考“静态结构如何承载业务语义”;第21题SSD图,表面考画法,实则考“如何把用户动作翻译成系统可响应的契约”;第24题GRASP五原则,表面考名词,实则考“当两个类都在抢一个职责时,你凭什么拍板?”
适合谁?不是零基础小白,而是已经画过几遍类图、却被“关联 vs 聚合 vs 组合”绕晕,或能画出顺序图却写不出对应代码的进阶学习者。你缺的不是知识点,是一张能让你从“会画”跃迁到“会设计”的导航图。

2. 静态结构建模:类图、对象图与关系语义的精确表达

UML静态结构图是系统设计的“骨骼”,但骨骼若错位,肌肉再发达也会瘫痪。类图(Class Diagram)作为最核心的静态图,其难点从来不在图形符号本身,而在于如何让每个连线、每个数字、每个箭头,都精准承载业务规则与设计意图。本章将拆解类图中极易被当作装饰的细节,还原它们背后的设计决策逻辑。

2.1 类图核心元素:属性、操作与可见性的真实含义

类图中的属性(Attribute)和操作(Operation)不是代码字段和方法的简单映射,而是职责的声明。例如,“客户”类中属性name: String,表面是存储姓名,深层职责是“保证客户身份可识别且符合业务规范”;操作placeOrder(): Order,表面是生成订单,深层职责是“协调库存校验、价格计算、订单持久化等子职责”。
可见性(Visibility)则是职责边界的守门员:

  • +(public):对外承诺的服务接口,调用方有权依赖;
  • #(protected):仅限子类继承复用,体现“父类为子类预留扩展点”的设计契约;
  • -(private):类内部私有实现,修改不影响外部,是封装的核心防线。

提示:考试中常考“可见性与封装目的”,答案必须指向“信息隐藏”(Information Hiding),而非“安全”或“保密”。封装的本质是控制变化影响范围——把实现细节藏起来,外部只依赖稳定接口,这样内部重构才不会牵一发而动全身。

2.2 四大关系辨析:关联、聚合、组合、泛化的业务语义鸿沟

UML关系是类图的灵魂,但也是错误重灾区。关键在于:每种关系都对应一段不可妥协的业务事实,画错关系=曲解业务本质。下表对比其核心语义与典型误用:

关系类型图形表示业务语义本质典型实例常见误用陷阱
关联(Association)实线连接,可标多重度两个类实例间存在长期、双向的认知联系“客户”与“订单”:一个客户可下多个订单,一个订单属于一个客户误将临时依赖(如“订单”调用“支付网关”)画成关联;忽略多重度标注导致语义模糊
聚合(Aggregation)空心菱形+实线“整体-部分”关系,部分可独立存在,生命周期不绑定“汽车”与“轮胎”:轮胎可单独销售、更换,不随汽车报废而销毁误将所有“包含”关系都画成聚合;混淆“可独立存在”与“逻辑上属于”
组合(Composition)实心菱形+实线强“整体-部分”关系,部分生命周期完全由整体控制,不可独立存在“订单”与“订单项”:订单删除,所有订单项必须同步删除;订单项不能脱离订单存在误将“强依赖”等同于组合(如“用户”与“用户配置”可能是关联而非组合)
泛化(Generalization)空心三角箭头“is-a”继承关系,子类是父类的特化,必须满足里氏替换原则“员工”泛化出“经理”、“工程师”:所有经理操作必须兼容员工接口误将“has-a”(拥有)关系画成泛化(如“订单”泛化“电子订单”是错的,应是关联)

实战验证:题目2中“类A由类B的一个实类和类C的1个或多个实类构成”,关键词“由……构成”且强调“一个B”和“一个或多个C”,表明B、C是A的组成部分,且A销毁时B、C应随之销毁(如“公司”由“CEO”和“部门”构成),故A与B、C均为组合关系,菱形端在A侧,多重度分别为1和1..*。

2.3 多重度:业务规则的数学化表达

多重度(Multiplicity)是类图中最具业务穿透力的符号,它把模糊的自然语言规则(如“一个客户可以下多个订单”)转化为精确的数学约束。其格式为min..max(如0..*)或单值(如1),必须标注在关联线两端,且每端的多重度描述的是“该端类的实例,能与另一端多少个实例关联”。
以题目3为例:“一个客户提交0个或多个订单;一个订单由一个且仅由一个客户提交”。

  • 对“订单”类实例:它必须关联恰好1个“客户”实例 → 客户端多重度为1;
  • 对“客户”类实例:它可以关联0个或多个“订单”实例 → 订单端多重度为0..*。
    因此,填空(46)选B(1个),(47)选D(0个或多个)。

注意:0..*≠*,1..*≠1。*是简写,但考试中要求写全称0..*;1表示“必须且唯一”,1..*表示“至少一个,可多个”。

2.4 包图与构件图:从逻辑分组到物理部署的层级跃迁

类图聚焦单个类,而包图(Package Diagram)和构件图(Component Diagram)解决更大尺度的组织问题:

  • 包图:对类、用例等模型元素进行逻辑分组,解决命名空间冲突与依赖管理。例如,将“用户管理”相关类放入<<package>> UserModule,其依赖<<package>> AuthModule,用虚线箭头标注<<use>>。关键原则是高内聚、低耦合——包内元素高度相关,包间依赖尽可能少且稳定。
  • 构件图:描述可独立编译、部署的物理单元(如JAR包、DLL、微服务),展示构件间的接口(Provided Interface)与所需接口(Required Interface),用lollipop(提供)和socket(需要)符号表示。例如,PaymentService构件提供IPayment接口,OrderService构件需要该接口,二者通过<<interface>> IPayment连接。

二者区别本质是抽象层级不同:包是设计时的逻辑容器,构件是运行时的物理实体。混淆二者会导致设计脱离实际——比如在包图中画数据库连接细节,或在构件图中纠结某个类的私有方法。

3. 动态行为建模:用例、交互与状态流转的时序逻辑

静态结构定义“是什么”,动态行为定义“怎么做”。UML动态图是业务逻辑的执行剧本,其核心挑战在于:如何让时间、状态、消息在图中既清晰可读,又严格符合现实世界的因果链条。本章聚焦三类高频考点图——用例图、交互图(顺序图/协作图)、状态图,揭示其背后的行为建模范式。

3.1 用例图:划定系统边界的“宪法性文件”

用例图(Use Case Diagram)不是功能列表,而是系统与外部世界(Actor)的契约声明。其核心元素仅有三个:Actor(参与者)、Use Case(用例)、关系(Association, Include, Extend)。

  • Actor:必须是系统外部的、能主动发起交互的实体(人、其他系统、硬件设备),绝非系统内部模块。例如,“电话用户”是Actor,“POS收款台”是系统内部组件,不能作为Actor。
  • Use Case:代表一个完整、有价值的目标,由Actor发起并获得可观察结果。例如,“使用电话卡”和“对方付款”是两个独立用例,因目标不同(付费方不同)、结果不同(扣费账户不同)。
  • 关系:
    • <<include>>(包含):强制依赖,被包含用例是主用例的必需子步骤(如“登录”被“查看订单”包含);
    • <<extend>>(扩展):可选增强,在特定条件下向基用例注入新行为(如“发送短信通知”扩展“完成支付”,仅当用户勾选通知时触发)。

提示:考试中常考“Actor识别”。牢记:Actor永远站在系统外面,且必须有主动性。例如,题目12中“电话用户”是Actor,而“电话卡系统”是另一个外部系统(可作为Actor),但“电话卡”本身是数据,不能是Actor。

3.2 交互图双雄:顺序图与协作图的互补性设计

顺序图(Sequence Diagram)与协作图(Collaboration Diagram,现称通信图)同属交互图,但设计哲学截然不同:

  • 顺序图:以时间轴为第一维度,生命线(Lifeline)垂直排列,消息水平箭头按时间自上而下流动。优势在于时序绝对清晰,尤其适合表现条件分支(alt)、循环(loop)、并发(par)等复杂流程。
  • 协作图:以对象空间关系为第一维度,对象用矩形框表示,连接线体现对象间关联,消息用带编号的箭头标注(如1.1,1.2,2)。优势在于对象拓扑结构一目了然,新增对象只需添加框和连线,无需重排整个图。

二者可无损转换,但考试中必须按题干要求作答。题目4、72、74均明确要求分析区别,核心得分点在于:
✅ 顺序图强调时间顺序(Time Ordering),协作图强调对象组织(Object Organization);
✅ 顺序图消息顺序由垂直位置决定,协作图由消息编号决定;
✅ 顺序图适合宏观流程设计(如用例主成功流),协作图适合微观对象协作细化(如某次支付的具体对象交互)。

实战代码映射:题目21要求画SSD图(系统序列图),其本质是简化版顺序图,只含Actor、系统边界框(System Boundary)、以及系统对外暴露的操作(如makeNewSale())。关键规则:

  • Actor发出消息到系统框,系统框内不画内部对象,只写操作名;
  • 消息编号从1开始,按时间递增;
  • 系统返回消息(如显示金额)用虚线箭头。
    例如,1: makeNewSale()→2: enterItem(itemID,quantity)→3: endSale()→4: makePayment(amount),编号即执行顺序。

3.3 状态图:捕捉对象生命周期的“状态机”

状态图(State Machine Diagram)描述单个对象在其生命周期内,响应事件所经历的状态变迁。其核心是三个要素:状态(State)、事件(Event)、动作(Action)。

  • 状态:对象在某一时刻的特征(如“订单”的Draft、Confirmed、Shipped、Cancelled);
  • 事件:触发状态变迁的外部刺激(如submitOrder()、cancelOrder());
  • 动作:状态变迁时执行的操作(如sendConfirmationEmail())。

关键易错点:
❌ 混淆“状态”与“活动”:状态图描述静止特征(如Processing),活动图描述动态过程(如“处理订单”包含多个步骤);
❌ 忽略初始状态(●)和终止状态(❩):每个状态图必须有且仅有一个初始状态,可有零个或多个终止状态;
❌ 事件标注不完整:必须写清事件名及可选参数(如paymentReceived(amount: Money)),而非仅写“付款”。

业务驱动设计:题目中未直接考状态图,但客户-订单关系隐含状态逻辑。例如,“订单”从Created→Paid→Shipped→Delivered,每个变迁需明确触发事件(如makePayment())和守卫条件(如[amount >= total])。

4. 职责分配建模:GRASP原则、设计模式与SSD契约的落地实践

如果说静态图定义“有什么”,动态图定义“做什么”,那么职责分配建模则定义“谁来做、为什么这么做”。这是UML从绘图工具跃升为设计方法论的关键一跃。本章直击复习痛点:GRASP原则为何难记?设计模式如何不背诵?SSD图怎样写出可执行代码?

4.1 GRASP五大原则:面向对象设计的“宪法准则”

GRASP(General Responsibility Assignment Software Patterns)不是技巧,而是分配职责的根本哲学。其价值在于:当面对“这个方法该放在哪个类?”的抉择时,提供可复用的决策框架。五原则必须结合场景理解,而非孤立记忆:

原则核心思想解决的问题典型反例代码级体现
信息专家(Information Expert)将职责分配给拥有执行该职责所需信息的类“谁该计算订单总价?”将计算逻辑放在Customer类(无价格信息),而非Order或Product类Order.calculateTotal()调用this.items.stream().map(Item::getPrice).sum()
创建者(Creator)将创建对象的职责分配给记录了该对象的实例、紧密使用该对象、或具有初始化数据的类“谁该创建新的订单项?”OrderService凭空new OrderItem(),而非由Order类的addItem()方法创建Order.addItem(product, quantity)内部new OrderItem(product, quantity)
低耦合(Low Coupling)最小化类之间的依赖,降低变更影响范围“修改支付方式是否要改订单类?”Order类直接依赖AlipaySDK,导致换微信支付需改OrderOrder依赖抽象IPaymentProcessor,具体实现由工厂注入
高内聚(High Cohesion)让一个类的职责高度相关,避免“万能类”“一个类既有用户认证又有报表生成?”UserService包含login(),logout(),generateSalesReport()拆分为AuthService(专注认证)和ReportService(专注报表)
控制器(Controller)将处理系统事件(如UI操作)的职责分配给非UI、非实体的协调类(如OrderController)“按钮点击事件直接在OrderView中写业务逻辑?”OrderView的onClick()方法里调用database.save(order)OrderView调用OrderController.handlePlaceOrder(),由Controller协调Order、Payment等服务

提示:题目24、52明确考查GRASP。注意“多态(Polymorphism)”虽是OOP特性,但不属于GRASP原则(题目52答案D正确),它是实现“低耦合”和“开闭原则”的技术手段,而非职责分配原则。

4.2 设计模式:GRASP原则的“标准化解决方案”

设计模式是GRASP原则在特定场景下的成熟实现。复习时切忌死记名称,而要抓住其解决的核心矛盾:

  • 单例模式(Singleton):解决“全局唯一实例”的管控问题。关键在线程安全的懒汉式实现(双重检查锁)或枚举式(最简洁)。
  • 策略模式(Strategy):解决“算法频繁变更”的问题。核心是定义算法族接口,让具体算法成为可插拔的实现类。
  • 组合模式(Composite):解决“统一处理树形结构中叶子与容器”的问题。关键在组合对象与叶子对象实现同一接口,客户端无需区分。
  • 适配器模式(Adapter):解决“现有接口不匹配新需求”的问题。核心是通过包装(Wrapper)或继承(Inheritance)转换接口。

代码示例:策略模式应对价格计算规则变更

// 1. 定义策略接口 public interface PricingStrategy { BigDecimal calculatePrice(OrderItem item); } // 2. 具体策略实现(可随时新增) public class StandardPricing implements PricingStrategy { public BigDecimal calculatePrice(OrderItem item) { return item.getProduct().getPrice().multiply(BigDecimal.valueOf(item.getQuantity())); } } public class DiscountPricing implements PricingStrategy { public BigDecimal calculatePrice(OrderItem item) { BigDecimal base = item.getProduct().getPrice().multiply(BigDecimal.valueOf(item.getQuantity())); return base.multiply(BigDecimal.valueOf(0.9)); // 9折 } } // 3. 在Order中注入策略(体现低耦合) public class Order { private PricingStrategy pricingStrategy; // 依赖抽象 public void setPricingStrategy(PricingStrategy strategy) { this.pricingStrategy = strategy; } public BigDecimal getTotal() { return items.stream() .map(pricingStrategy::calculatePrice) // 委托给策略 .reduce(BigDecimal.ZERO, BigDecimal::add); } }

此设计下,新增促销策略只需添加新PricingStrategy实现类,Order类完全无需修改,完美践行开闭原则(对扩展开放,对修改关闭)。

4.3 SSD图与操作契约:从用户动作到代码契约的桥梁

SSD(System Sequence Diagram)是连接需求与设计的关键枢纽。它只画Actor与系统边界,不涉及内部对象,目的是明确“系统对外承诺什么”。其输出是操作契约(Operation Contract),一份描述系统操作前后状态变化的契约文档。
契约三要素:

  1. 前置条件(Pre-condition):操作执行前系统必须满足的状态(如“客户已登录”);
  2. 后置条件(Post-condition):操作执行后系统必须达成的状态(如“创建新订单,订单状态为Draft”);
  3. 系统事件(System Event):触发操作的输入(如makeNewSale())。

SSD图 → 契约 → 代码的转化链:
题目21的SSD:1: makeNewSale()→2: enterItem(...)→3: endSale()→4: makePayment(...)
对应endSale()操作契约:

  • Pre-condition: 至少有一个商品已录入;
  • Post-condition: 创建Sale对象,状态为Completed,totalAmount等于所有商品价格之和;
  • System Event:endSale()

此契约直接指导Sale类设计:

public class Sale { private List<SaleItem> items = new ArrayList<>(); private BigDecimal totalAmount; private SaleStatus status; // 契约要求:endSale()后totalAmount必须准确计算 public void endSale() { this.totalAmount = items.stream() .map(item -> item.getPrice().multiply(BigDecimal.valueOf(item.getQuantity()))) .reduce(BigDecimal.ZERO, BigDecimal::add); this.status = SaleStatus.Completed; } }

5. 易错点与易漏点:那些阅卷老师一眼揪出的“设计破绽”

复习中最痛的不是不会,而是“以为会,实则错”。这些易错点往往藏在题干细微处、符号歧义中、或思维惯性里。以下是根据真题高频错误整理的5条血泪经验,每一条都对应一个真实翻车场景:

5.1 易漏点:多重度标注位置颠倒——业务语义彻底反转

易漏点:在关联线上,将多重度标在错误的一端。
为什么漏:初学者常按“读句子顺序”标注(如“客户有多个订单”,就标在客户端0..*),而UML规定多重度描述的是“该端实例能关联另一端多少个实例”。
怎么补:牢记口诀——“看箭头,标对面”。无论关联线如何画,先确定你要描述的类(如“订单”),然后看它与“客户”的连线,多重度标在客户那一端,因为这是在说“一个订单对应几个客户”。题目3中(46)问“每个订单对应几个客户”,答案必是1,标在客户端;(47)问“每个客户对应几个订单”,答案0..*,标在订单端。画图时,先写类名,再画线,最后标多重度,强迫自己思考“这个数字是描述哪边的”。

5.2 易错点:聚合与组合的“生命周期”误判——混淆逻辑包含与物理归属

易错点:看到“由……组成”就画组合,忽视“部分能否独立存在”。
为什么错:中文“组成”一词模糊,如“公司由部门组成”,但部门可独立存在(公司解散,部门可能并入其他公司),应为聚合;而“订单由订单项组成”,订单项绝不能脱离订单,才是组合。
怎么补:做“删除测试”——如果删除整体,部分是否必须同时删除?是→组合;否→聚合;若部分根本无法独立存在(如“心脏”之于“人体”),则是组合。题目2中“类A由类B的一个实类构成”,若B是“CEO”,A是“公司”,CEO可跳槽,故应为聚合(空心菱形),而非组合。考试中若题干未明确“生命周期绑定”,默认按聚合处理。

5.3 易忽略点:协作图消息编号的层级逻辑——时序混乱的根源

易忽略点:协作图中消息编号仅用1,2,3...,未体现嵌套调用的层级。
为什么忽略:顺序图用垂直位置天然体现层级,协作图需人工编号,易被当成简单序号。
怎么补:采用小数点层级编号:主调用为1,2;1引发的子调用为1.1,1.2;1.1引发的孙调用为1.1.1。例如,1: makeNewSale()→1.1: createSale()→1.1.1: generateId()。题目4明确指出“协作图用消息编号表示时间顺序”,编号必须体现调用栈深度,否则无法还原时序。

5.4 易错点:用例图中Include/Extend关系的方向——契约义务的倒置

易错点:<<include>>箭头从基用例指向被包含用例,却画成反方向。
为什么错:误将“包含”理解为“基用例拥有被包含用例”,而<<include>>表示“基用例必须调用被包含用例”,箭头方向是控制流方向(谁调用谁)。
怎么补:记住<<include>>是“强制调用”,箭头从调用方(基用例)指向被调用方(被包含用例);<<extend>>是“可选增强”,箭头从扩展用例指向基用例(扩展用例“注入”到基用例)。题目12中“使用电话卡”和“对方付款”是并列用例,无包含/扩展关系,应各自独立连接到Actor。

5.5 易漏点:SSD图中系统边界框的“黑匣子”属性——画出内部细节即失分

易漏点:在SSD图中,于系统边界框内画出Order、Payment等内部类或对象。
为什么漏:混淆SSD与详细顺序图。SSD的唯一使命是界定系统对外接口,内部实现是黑盒。
怎么补:SSD图中,系统边界框(System Boundary)内只允许出现操作名(如makeNewSale()),绝不出现类名、对象名、属性或方法细节。题目51明确给出答案D:“不对系统的内部结构与功能进行描述”。画图时,先画Actor,再画一个矩形框标“System”,最后在框内写操作名,三步之外,全是多余。

6. 复习清单与查漏补缺:构建你的UML设计能力自检体系

复习到最后,拼的不是刷题量,而是能否在脑中快速调取一张完整的UML能力地图,并精准定位薄弱环节。以下是一份可立即执行的查漏补缺清单,覆盖知识、技能、思维三层,帮你把零散考点织成一张可随时调用的设计网络。

6.1 知识层:9大UML图的“一句话定位”与“必考参数”

UML图太多?先用一句话锚定其不可替代性,再抓核心参数。下表按考试权重排序(高频→低频):

图类型一句话定位必考参数/符号易错陷阱
类图系统静态结构的“DNA图谱”关联多重度(两端!)、聚合/组合菱形(空心/实心)、泛化箭头(空心三角)多重度标错端;组合误画为关联
用例图系统与外界的“宪法契约”Actor(必须外部)、<<include>>/<<extend>>箭头方向、用例命名(动宾结构)Actor画成内部类;<<include>>箭头反向
顺序图时间轴上的“事件流水账”生命线(Actor/对象)、同步消息(实线箭头)、返回消息(虚线箭头)、激活框(控制焦点)返回消息遗漏;条件框alt未标[guard]
协作图对象关系网的“社交图谱”对象框、连接线、消息编号(1,1.1,2)、自调用(弯曲箭头)编号无层级;遗漏连接线
状态图单个对象的“人生轨迹图”初始状态(●)、状态名(圆角矩形)、事件/动作(event[guard]/action)、终止状态(❩)事件无参数;状态名用动词(错!)
活动图业务流程的“泳道流程图”活动节点(圆角矩形)、决策点(菱形)、分叉/汇合(粗线)、泳道(分区)混淆状态图(状态变迁)与活动图(动作执行)
包图逻辑模块的“行政区划图”包图标(带标签的文件夹)、依赖箭头(虚线+<<use>>)包内画类细节;依赖箭头标错方向
构件图物理单元的“积木组装图”构件图标(矩形+< >)、接口符号(lollipop/socket)接口名未标注;构件间画关联而非依赖
部署图硬件拓扑的“机房布线图”节点(立方体)、构件部署(虚线箭头)、连接(<<connect>>)节点名用软件名(如“Web服务器”应为“AppServer”)

自查方法:遮住“一句话定位”栏,看到图名能否脱口而出其核心使命?遮住“必考参数”栏,能否默画出该图最关键的3个符号?任一卡壳,即为知识盲区。

6.2 技能层:从题干到图表的“四步解码法”

考试中,80%的失分源于“读懂题干却画错图”。掌握这套解码法,让题干指令自动映射到图表元素:

  1. Step 1:抓主体(Who)

    • 找出所有名词(类、Actor、状态、用例),它们是图中的节点;
    • 例题3:“客户”、“订单” → 类图中的两个类;“电话用户” → 用例图中的Actor。
  2. Step 2:析关系(How)

    • 找出所有动词与数量词(“提交”、“由……构成”、“0个或多个”),它们决定连线与多重度;
    • 例题2:“类A由类B的一个实类和类C的1个或多个实类构成” → A与B是1对1关联,A与C是1对多关联。
  3. Step 3:定类型(What Kind)

    • 根据题干关键词判断关系类型:
      • “由……构成”、“整体-部分” → 聚合/组合;
      • “是……的一种” → 泛化;
      • “使用”、“依赖” → 依赖;
      • “需要”、“调用” → 关联。
  4. Step 4:验约束(Check)

    • 对照UML语义检查:
      • 多重度是否满足业务规则?(如“一个订单只能由一个客户提交” → 订单端客户多重度必为1);
      • Actor是否在系统外?(“POS收款台”是系统内部,不能是Actor);
      • SSD图中系统框内是否只有操作名?(绝不能出现Order类)。

实战演练:题目9的销售实例,“a,b,c,d”填空。题干“销售”与“商品”、“销售”与“顾客”、“商品”与“商品说明”——Step1抓名词;Step2“销售包含商品”、“销售属于顾客”、“商品有说明” → Step3判断为组合、关联、关联;Step4验:销售与商品是强组合(1..*),销售与顾客是关联(1),商品与说明是关联(1),故a=1, b=1.., c=1, d=1..。

6.3 思维层:GRASP与设计模式的“决策树”

面对设计题,不再靠背诵,而是用决策树快速定位原则:

graph TD A[新职责要分配] --> B{谁拥有执行所需信息?} B -->|是| C[信息专家:给该类] B -->|否| D{谁记录/紧密使用/初始化该对象?} D -->|是| E[创建者:给该类] D -->|否| F{是否需降低依赖?} F -->|是| G[低耦合:引入接口/中介] F -->|否| H{是否职责过多?} H -->|是| I[高内聚:拆分或转移] H -->|否| J{是否处理系统事件?} J -->|是| K[控制器:给非UI协调类] J -->|否| L[重新审视:是否违反单一职责?]

模式选择口诀:

  • 要“唯一” → 单例;
  • 要“换算法” → 策略;
  • 要“统一处理树” → 组合;
  • 要“连旧接口” → 适配器;
  • 要“解耦发布-订阅” → 观察者。

从那以后我每次拿到设计题,都强制走一遍这张决策树:先问“信息在哪”,再问“谁创建”,最后问“要不要解耦”。哪怕一时想不起模式名,也能推导出“这里需要一个接口”,比死记硬背可靠十倍。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询