面向对象与 UML 专题 · 考点 · 怎么考 · 真题全解
软考 · 软件设计师 | 上午 8~11 分 (OO概念/UML/设计原则/设计模式)+ 下午第 3 题 UML 建模(15 分·必答) + 第 5/6 题 设计模式(15 分·选一)
本页所有真题均为原题 ,附原始配图 (base64 内嵌)、官方答案 与怎么做(解题动作) 。
⏱ 考前 10 分钟速览(点击展开/收起)
① 每种图"建模什么"(上午必考): 类图=系统的词汇 · 对象图=对象快照 · 用例图=外部可见服务 · 活动图=系统内活动到活动的流程 · 状态图=反应型对象 · 构件图=静态结构。
② 类图 6 关系(强→弱): 组合 > 聚合 > 关联 > 依赖;泛化/实现另算。实心菱=组合(同生共死) 、空心菱=聚合(可分离) 、空心三角实线=泛化(继承) 、空心三角虚线=实现(implements) 。
③ 用例 3 关系: include=每次必做的公共部分;extend=可选的条件分支;generalize=子用例继承父用例(泛化)。
④ 三个易混: 覆盖(Override)=子类重写父类、同名同参;重载(Overload)=同类同名不同参;多态=同一消息不同结果。静态绑定=编译时、动态绑定=运行时(=多态的实现手段) 。
⑤ 多态 4 类: 参数(泛型/模板) · 包含(子类型/继承) · 过载(同名不同上下文) · 强制(类型转换)。
⑥ OOA/OOD/OOP: OOA 分析=认定对象→组织对象→描述相互作用→确定操作;OOD 设计=识别类及对象→定义属性→定义服务→识别关系→识别包 ;OOP=用语言实现。带"包/属性/服务"=OOD。
⑦ 设计原则信号词: 只一种功能/唯一修改原因=单一责任;不强迫客户依赖不用的方法=接口分离;重用成组=共同重用;变化 影响整包=共同封闭;包图无环=无环依赖;依赖抽象=依赖倒置;子类可替换父类=里氏替换。
⑧ 设计模式: 创建5 / 结构7 / 行为11;类模式只有 4 个 (工厂方法、适配器-类、解释器、模板方法),其余皆对象模式。
⑨ 模式识别信号(见词选词): 转换接口=Adapter · 树形/部分整体=Composite · 多方案可切换=Strategy · 逐级传递/多对象处理=责任链 · 对象间不直接引用=Mediator · 状态变行为=State · 封装请求/可撤销=Command · 存档恢复=Memento · 一变全通知=Observer · 对外统一接口=Facade · 共享省内存=Flyweight · 算法骨架=Template Method。
⑩ 状态图三要素: 无括号=事件;方括号 [ ]=监护条件 ;斜杠后 /动作=转换后效果。状态图→反应型对象;when()=变化 事件(非时间事件)。
⑪ 下午第 3 题(UML·必答): 参与者=需求里"跟系统打交道的外部角色";用例=动宾短语 ;类=需求里的名词 ;再按图中箭头形状填关系(空心三角=泛化)。
⑫ 易错答案提醒: 2021上 状态图题=BBD (41 状态图→反应型对象 / 42 状态A与B动作全完成 / 43 不正确的是"状态由事件触发");2021下 登录状态图=B / 监护条件 / 转换后效果 ;2022下 鸭子题=37 继承(A)、38 多态(D) (不是"动态绑定") —— "动态绑定"只是实现多态的手段。
★ 考点与怎么考(先看这个)
软考面向对象这块,上午考概念识别,下午考照着需求补图/填代码 。分值分布与考法如下(依据 2020下~2023上 真题统计):
考试位置 分值 考什么(考点) 怎么考(题型动作)
上午 · OO基本概念 2~3 对象三要素、封装/继承/多态、覆盖vs重载、静态/动态绑定、消息、多态4分类 给一句定义→选术语;或给场景判断体现哪种机制
上午 · OOA/OOD活动 1~2 分析/设计各阶段的活动顺序(认定对象 vs 识别类及对象…) 给一串活动→判断属于 OOA 还是 OOD
上午 · 类图关系 1~2 依赖/关联/聚合/组合/泛化/实现 的区别与辨图 给一句"整体-部分、同生共死/可分离"→选关系
上午 · UML图用途 1~2 状态图=反应型对象;活动图=流程;构件图=静态结构;用例图=外部可见服务 "××图用于建模( )"
上午 · 设计原则 1~2 单一责任/开闭/里氏替换/依赖倒置/接口分离/共同重用/共同封闭/无环依赖 给一段原则描述→选原则名(抓关键词)
上午 · 设计模式 2~4 23种模式的意图与所属类别(创建/结构/行为、类/对象) 给场景/类图→选模式名 + 选分类
下午 · 第3题 UML 15 用例图(参与者/用例)、类图(类名/属性/多重度)、用例关系 读需求→补 A/U/C 编号 + 解释 include/extend/泛化
下午 · 第5/6题 模式 15 Comosite/Observer/Strategy/Memento/Facade/Mediator/Flyweight… 的类图+代码 看类名猜模式 → 按模式结构补 Java/C++ 空
🎯 一句话策略 :
上午这 8~11 分几乎全是"认概念/认图" ,把下面①②③④⑤⑥六节背熟即可;
下午第3题必答 ,得分点=参与者名、用例名、类名、几个关系名——都是需求里的名词/动词 ,会读需求就会填;
下午第5/6题选一 ,挑自己语言熟的那份,按"标准模式类图"套。
① OO 基本概念 object-oriented basics
面向对象 = 对象 + 分类 + 继承 + 通过消息的通信 。
1
对象(Object) 现实里能独立存在、有状态有行为的一个东西。三要素:属性(数据)+ 方法(操作)+ 对象 ID 。
2
类(Class) 对一组相同属性/方法的对象的抽象 (模板)。分 实体类 (数据)/ 控制类 (协调流程)/ 边界类 (与外界交互)。
3
封装 把属性和实现细节藏起来 ,只暴露接口(信息隐藏)。
4
继承/泛化 子类复用父类,讲"是不是"(is-a)。考试信号:看到"特殊/一般" → 泛化。
6
覆盖 vs 重载 覆盖/重置 :子类重写父类方法(同名同参);重载 :同一类里同名不同参。
7
静态绑定 vs 动态绑定 静态绑定 :编译时结合(如重载);动态绑定 :运行时 结合(如覆盖→多态)。
💡 多态的 4 分类(2020下 Q40 考点·细讲)
"多态"太宽,教材按实现机制 把它分成 4 类,再归成两组:通用多态 (参数/包含)、特定多态 (过载/强制)。用 Java 一看就懂:
1
参数多态 Parametric ——"模板/泛型"
一份代码靠类型参数 适配多种类型。
List<String> a; 与 List<Integer> b; —— 同一个 List,参数不同、结构不变。
考试信号:模板 / 泛型 / 类型参数 。
2
包含多态 Inclusion ——"子类型化"
子类型可出现在父类型位置(is-a),运行时才决定调哪个子类 → 动态多态 。
Animal a = new Bird(); a.move();
考试信号:子类型 / 向上转型 / 父子类 。软考平时说的"多态"多指这个。
3
过载多态 Overloading ——"同名不同义"(★本题答案)
同一个名字在不同上下文中含义不同 :方法重载、运算符重载。
void f(int x){} 与 void f(String s){} —— 同名 f,参数不同 → 不同实现,编译时 就能定 → 静态多态。
考试信号:同一名字、不同上下文、重载 。
4
强制多态 Coercion ——"类型强转"
编译器把类型自动/强行转换以匹配需要。
double d = 1 + 2.5; —— int(1) 被强制转成 double。
考试信号:类型转换 / 强制转换 。
🎯
速查表(抓题干关键词 → 秒选) :
题干关键词 答案
模板 / 泛型 / 类型参数 参数 多态
子类型 / 向上转型 / 父子类 包含 多态
同一个名字在不同上下文含义不同 / 重载过载 多态
类型转换 / 强制转换 强制 多态
组别记忆:
参数/包含 = 通用多态;过载/强制 = 特定多态 。
静/动绑定:
静态多态 = 过载、参数多态 (编译时定);
动态多态 = 包含多态 (运行时定,即绑定到覆盖)。
💡 OOA / OOD / OOP 是什么、怎么考(真题考过 2 次活动顺序)
面向对象软件开发把传统开发流程"面向对象化",分三个大阶段:OOA(分析)→ OOD(设计)→ OOP(编程实现) 。软考就是拿这三阶段各自的活动 来考你区分。
1
OOA 面向对象分析 —— 解决"做什么"
面向问题域 ,抽取对象,建立独立于实现的问题域模型 (就是需求里的对象/关系)。
经典活动顺序(2021上 Q37 答案 ):认定对象 → 组织对象 → 描述对象的相互作用 → 确定对象的操作 。
2
OOD 面向对象设计 —— 解决"怎么做"
把分析模型加工成可实现的求解域模型 ,加入与实现有关的设计(分模块、定接口、加类)。
活动顺序(2021下 Q37 答案 ):识别类及对象 → 定义属性 → 定义服务 → 识别关系 → 识别包 。
OOD 又分两步:高层设计 (划分子系统、确定交接口)+ 类设计 (细化类的属性/方法/可见性)。
3
OOP 面向对象编程 —— "选一门语言去实现"
用一种 OO 程序设计语言把设计写出来。
(2022上 Q19 :"面向对象实现 "就是 OOP,选语言这一步。)
对比项 OOA 分析 OOD 设计
目标 搞清"做什么 "(问题域) 搞清"怎么做 "(求解域)
核心活动 认定对象、组织对象、描述相互作用、确定操作 识别类及对象、定义属性、定义服务、识别关系、识别包
与实现无关? 无关 (不关心语言/平台)有关 (考虑实现约束)
对应真题 2021上 Q37 / 2022上 Q18 2021下 Q37
🔑 一句话区分 :
看到"认定对象 、组织对象、描述相互作用" → OOA ;
看到"识别类及对象 、定义属性、定义服务 、识别关系、识别包" → OOD ;
看到"选一种 OO 程序设计语言/编码" → OOP(实现) 。
⚠️ 陷阱:两个活动表前两项很像(都先找对象),靠"定义服务/识别包"这个尾巴认 OOD ;OOA 的尾巴是"确定对象的操作 / 描述相互作用 "。
📌 别混淆:OOA/OOD/OOP 是"开发阶段 "(分析→设计→实现);
封装/继承/多态 是"OO 的机制 ";
UML 是"建模语言 "(三个阶段都能用它画图)。
② 类图 6 种关系 class relationships
依赖 临时用 虚线开口箭头
关联 长期持有 实线
聚合 整体-部分·可分离 空心菱形
组合 整体-部分·同生共死 实心菱形
关系 含义 图记 判断信号
依赖 A 临时用到 B 虚线 + 开口箭头 B 是 A 方法参数/局部变量
关联 对象间长期连接 实线(可带方向/多重度) A 里有 B 的成员变量
聚合 整体-部分,生命周期不同 空心菱形(菱形在整体端) 部分可独立存在;"网店◇-商品"
组合 整体-部分,生命周期相同 实心菱形(菱形在整体端) 整体没部分也没;"订单◆-订单行"
泛化 特殊/一般(is-a) 实线 + 空心三角(指父) 看到"特殊/一般"
实现 类实现接口 虚线 + 空心三角(指接口) 接口与类之间
🧠 口诀:"三角都空心" (泛化实线、实现虚线);"实心菱=死都不分(组合)、空心菱=可拆伙(聚合)" 。
子类
泛化(继承) 实线空心三角
实现 虚线空心三角
依赖 虚线开口箭头
关联 实线
聚合 空心菱形
组合 实心菱形
菱形永远画在"整体"那一端
类图 6 种关系图记速览
③ 用例图 3 种关系 usecase relationships
1
包含 include 从多个用例提取公共行为 。方向:基本用例 → 公共用例 ;关键词"每次都做"。
2
扩展 extend 基本用例的可选/特殊分支 。方向:扩展用例 → 基本用例 ;关键词"可做可不做"。
3
泛化 generalize 共性抽象为父用例,子用例继承父用例的结构/行为/关系。方向:子用例 → 父用例 。
基本用例
公共用例
«include»
扩展用例
基本用例
«extend»
子用例
子用例
父用例
include(基本→公共)|extend(扩展→基本)|generalize(子→父)
④ UML 图族总览 UML diagrams
类别 图名 用途(题干关键词 = 答案)
结构(静态) 类图 一组类、接口及关系
对象图 某一时刻一组对象及关系(对象快照)
构件图 构件之间的组织与依赖,专注静态结构
部署图 软件到硬件的物理部署
包图 包与包的依赖、分组
行为(动态) 用例图 系统对外提供的外部可见服务
活动图 系统内从一个活动到另一个活动的流程
状态图 对反应型对象 建模:状态随事件转换
序列图/协作图 对象间按时间顺序的交互
🎯 必背对应:"外部可见服务"→用例图;"活动到活动流程"→活动图;"反应型对象/生命周期状态"→状态图;"构件组织依赖·静态"→构件图;"对象快照"→对象图。
⑤ 面向对象设计原则 design principles
原则 一句话 题干信号
单一责任 SRP 一个类只做一种功能,修改原因唯一 "只做一种功能/一个修改原因"
开放-封闭 OCP 对扩展开放、对修改关闭 "不改原代码加功能"
里氏替换 LSP 子类可替换父类 "子类可替换父类"
依赖倒置 DIP 依赖抽象而非具体 "依赖抽象,不依赖具体"
接口分离 ISP 不强迫客户依赖不用的方法 "不强迫客户依赖不用的方法"
共同重用 CRP 重用包中一个类就要重用全部 "重用其一→重用全部"
共同封闭 CCP 包中所有类对同一种变化 共同封闭 "一个变化影响整包"
无环依赖 ADP 包依赖图中不允许有环 "包依赖图不能有环"
⑥ 设计模式分类 + 速记表 design patterns
类别 类模式(靠继承) 对象模式(靠组合)
创建型 Factory Method 工厂方法 Abstract Factory 抽象工厂、Builder 构建器、Prototype 原型、Singleton 单例
结构型 Adapter 适配器(类) Bridge 桥接、Composite 组合、Decorator 装饰、Facade 外观、Flyweight 享元、Proxy 代理
行为型 Interpreter 解释器、Template Method 模板方法 Chain of Responsibility 职责链、Command 命令、Iterator 迭代器、Mediator 中介者、Memento 备忘录、Observer 观察者、State 状态、Strategy 策略、Visitor 访问者
模式 意图 / 场景关键词 速记
Factory Method 定义创建接口,子类决定实例化哪个类 动态生产对象
Abstract Factory 创建一系列相关对象 生产成系列对象
Builder 复杂对象构造与表示分离 复杂对象构造
Prototype 拷贝原型创建对象 克隆对象
Singleton 保证唯一实例、全局访问点 单实例
Adapter 转换接口使原本不相容的协同工作 转换接口
Bridge 抽象与实现分离,各自独立变化 继承树拆分
Composite 树型"整体-部分",单/组合对象一致使用 树形目录
Decorator 动态添加职责 动态附加职责
Facade 为子系统一组接口提供统一高层接口 对外统一接口
Flyweight 共享大量细粒度对象 汉字编码
Proxy 提供代理控制访问 快捷方式
Chain of Responsibility 多个对象有机会处理请求,链接传递 传递职责
Command 请求封装成对象,可参数化/排队/撤销 日志记录·可撤销
Interpreter 定义文法并解释句子 虚拟机的机制
Iterator 顺序访问聚合元素 数据集
Mediator 用中介封装对象交互,降低耦合 不直接引用
Memento 保存/恢复对象内部状态 游戏存档
Observer 一对多依赖,状态改变自动通知 联动通知
State 内部状态改变时改变行为 状态变成类
Strategy 封装可互换的算法 多方案切换
Template Method 定义算法骨架,步骤延迟到子类 框架
Visitor 不改变元素类定义新操作 数据与操作分离
🎯 类模式只有 4 个 :Factory Method、Adapter(类)、Interpreter、Template Method;其余都是对象模式 。选项带"对象"的通常优先。
⑦ 上午真题(原题 + 原图 + 官方答案)
2020 下(11月)上午 · Q37–40
Q37 面向对象程序设计语言关键字
面向对象程序设计语言 C++、Java 中,关键字( )可以用于区分同名的对象属性和局部变量名。
A. private B. protected C. public D. this
答案 D(this) 。
小白版: 类里有个"成员变量"(对象属性),方法里又声明了同名的"局部变量"时,光写名字,程序会优先认局部变量 ;那想用对象的属性怎么办?加 this. 前缀——this 代表"当前这个对象 ",this.name 就明确指向对象属性。
为什么别的选项错: A/B/C(private/protected/public)是访问修饰符 ,管的是"谁能看见这个成员"(私有/受保护/公开),跟"名字冲突"无关。
Java 例子: class Dog{ String name; Dog(String name){ this.name = name; } }——参数 name 和成员 name 同名,this.name=成员,右边 name=参数。
口诀: 区分同名成员与局部变量 → 一律选 this(Python 里对应 self)。
Q38 一般-特殊关系
采用面向对象方法进行系统开发时,以下与新型冠状病毒有关的对象中,存在"一般-特殊"关系的是( )。
A. 确诊病人和治愈病人 B. 确诊病人和疑似病人 C. 医生和病人 D. 发热病人和确诊病人
答案 D 。
小白版:"一般-特殊"就是"继承"(泛化) ,判断诀窍一句话:"X 是不是一种 Y?" 能通顺说出"X is a Y",就是一般-特殊,Y 是一般(父类),X 是特殊(子类)。
逐项验证: A 确诊病人 vs 治愈病人——这是同一个人在不同阶段 的状态,属于"变化",不是"一种";B 确诊 vs 疑似——两者互斥,一个人只能二选一,不构成包含;C 医生 vs 病人——完全不同的角色,没有上下位;D 确诊病人是一种发热病人 (从发热人群里筛出确诊者)→ 成立,选 D。
对照 UML: 一般-特殊 = 泛化关系 = 类图里"空心三角实线 "箭头,箭头指向父类。
Q39 设计原则
进行面向对象系统设计时,针对包中的所有类对于同一类性质的变化:一个变化若对一个包产生影响,则对该包中所有类产生影响,而对其他包不造成影响。这属于( )设计原则。
A. 共同重用 B. 开放-封闭 C. 接口分离 D. 共同封闭
答案 D(共同封闭 CCP) 。
小白版: 包(package)就是把一堆相关的类装在一起。这条原则说:同一个包里的类应该"一起变化" ——需求一变要改这个包,就让包里所有相关的类一起改,别去连累别的包。
怎么一眼认出它: 题干出现关键词 "变化" (一个变化影响包里所有类、对其他包无影响)→ 选共同封闭 。
别跟"共同重用"混: 共同重用 (CRP)说的是"重用其中一个,就得重用全部 ";共同封闭 说的是"一起被变化影响 "。记:看到"变化"选封闭,看到"重用"选重用 。
Q40 多态分类
多态有不同的形式,( )的多态是指同一个名字在不同上下文中所代表的含义不同。
A. 参数 B. 包含 C. 过载 D. 强制
答案 C(过载多态) 。
小白版:多态有 4 种 ,题干说"同一个名字、在不同上下文含义不同 ",这就是过载多态 (同一个方法名 add(int) 与 add(String) 因参数不同做不同的事,即"重载")。
4 种对照记忆(死记):
∘ 参数多态 ——靠"模板/泛型"(List<T>),最通用;
∘ 包含多态 ——靠"子类型化/继承"(父类引用指向子类对象,运行时动态绑定);
∘ 过载多态 ——靠"同一名字不同上下文"(重载);
∘ 强制多态 ——靠"类型强制转换"((int)3.14、隐式转换)。
口诀: 名字同含义异→过载 ;模板→参数 ;子类型→包含 ;强转→强制 。详细例子见 ① 节「多态的 4 分类」 。
2021 上(5月)上午 · Q37–43、Q44–47
Q37 OOA 活动顺序
面向对象分析时,执行的活动顺序通常是( )。
A. 认定对象、组织对象、描述对象的相互作用、确定对象的操作
B. 认定对象、定义属性、组织对象、确定对象的操作
C. 认定对象、描述对象间的相互作用、确定对象的操作、识别包
D. 识别类及对象、识别关系、定义属性、确定对象的操作
答案 A 。
小白版: 面向对象分析(OOA)就是"从需求里找出系统有哪些对象 ",步骤固定为 4 步:
① 认定对象 (先在需求里找出有哪些名词/实体);② 组织对象 (把相关的对象归归类、理清层次);③ 描述对象间的相互作用 (谁给谁发消息、怎么协作);④ 确定对象的操作 (每个对象要提供哪些功能/方法)。
怎么排除干扰项: B 里"定义属性"是后面设计阶段才细化的;C 里"识别包"属于设计(OOD);D 顺序也不对。
一句话记: 认定 → 组织 → 描述相互作用 → 确定操作 ;只要选项里出现"识别包 / 定义服务 / 定义属性 ",那是 OOD(设计) 不是 OOA(分析)。
Q38 设计原则
采用面向对象方法进行系统设计时,不应该强迫客户依赖于他们不用的方法,接口属于客户,不属于它所在的类层次结构。即:依赖于抽象,不要依赖于具体。这属于( )。
A. 单一责任 B. 开放-封闭 C. 接口分离 D. 里氏替换
答案 C(接口分离 ISP) 。
小白版: 接口分离的意思是"别把一个大接口硬塞给所有客户 "。如果某个客户只用到接口里的 2 个方法,却被逼着实现另外 8 个用不到的方法,就是坏设计。正确做法是把大接口拆成几个专门的小接口,让客户只依赖自己真正要用的那个。
关键词抓取: "不应该强迫客户依赖他们不用的方法 "、"接口属于客户" → 立刻选接口分离 。
易混区分: 依赖倒置=依赖抽象不依赖具体;单一责任=一个类只干一件事;里氏替换=子类能替换父类不出错。本题强调"客户 "和"用不到的方法 ",只有接口分离对得上。
Q39 继承关系判断
Bird 和 Cat 是 Animal 的子类,Parrot 是 Bird 的子类;bird、cat、parrot 分别是各类对象。以下叙述不正确 的是( )。
A. cat 和 bird 可看作是 Animal 的对象 B. parrot 和 bird 可看作是 Animal 的对象
C. bird 可以看作是 Parrot 的对象 D. parrot 可以看作是 Bird 的对象
答案 C("bird 可以看作是 Parrot 的对象"是不正确的) 。
小白版: 继承关系里有一条铁律——子类对象可以当父类对象用,反过来绝对不行 。因为子类"是一种"父类(Parrot 是一种 Bird,Bird 是一种 Animal),所以"往下兼容",但不"往上兼容"。
逐项验证(问"X 是不是能看成 Y 的对象"):
∘ A. cat 和 bird 都是 Animal 的子类对象 → 能当 Animal 用 ✔
∘ B. parrot(Bird 的子类对象)和 bird 都能当 Animal 用 ✔
∘ C. bird 是 Bird 的对象,但不是 Parrot 的对象 ——Bird 范围更大,把"鸟"硬说成"鹦鹉"是错的 ✘(本题选它)
∘ D. parrot 是 Parrot 的对象,而 Parrot 是 Bird 的子类 → 能当 Bird 用 ✔
口诀: 向上转型(子→父)永远安全;向下转型(父→子)必须确认,不能乱说。题目问"不正确"→ C。
Q40 多态
Animal 定义接口 move(),Bird、Cat、Parrot 各自实现;调用 move() 时不同对象收到同一消息产生各自不同结果,这一现象称为( )。
A. 封装 B. 继承 C. 消息传递 D. 多态
答案 D(多态) 。
小白版: "同一消息,不同对象,不同结果 "——这就是多态 最核心的一句话定义。父类定好 move(),Bird、Cat、Parrot 各自实现;你调 animal.move() 时,Bird 会飞、Cat 会走、Parrot 会飞,同一个调用动作产生不同行为。
为什么不是别的:
∘ A 封装——是把数据和方法"包"起来隐藏细节,跟"不同结果"无关;
∘ B 继承——是"复用父类"的机制(它们确实用了继承,但题干问的是"调用后产生不同结果"这个现象 );
∘ C 消息传递——只是"对象之间发消息"的动作本身,不强调不同结果。
关键区分: 继承是"原因/机制 ",多态是"结果/现象 ";题干问"产生不同结果这一现象"→ 多态。
Q41–43 UML 状态图(含原图 · 逐问详解)
当 UML 状态图用于对系统、类或用例的动态方面建模时,通常是对(41)建模。以下 UML 状态图中,假设活动的状态是 A,事件 b=0 发生并且 a>5,发生条件是 C 状态到 D 状态的转换条件的是(42),D 变为活动的状态,有关状态图的叙述中,不正确的是(43)。
2021 上 · 状态图(原图)
(41) A. 系统的词汇 B. 反应型对象 C. 活动流程 D. 对象快照
(42) A. 一旦状态 A 的 exit 动作完成或如果当前执行 do 动作,则终止执行 B. 一旦状态 A 和 B 的所有动作完成 C. 一旦正在进行的状态 A 完成 D. 一旦状态 B 的 exit 动作完成
(43) A. 动作可以在状态内执行,也可以在状态转换时执行 B. 当触发转换的事件发生并且转换没有指定的监护条件时,对象将离开当前状态,并且其 do 动作终止 C. when(b=5) 称为时间事件 D. 状态由事件触发
(41) B (42) B (43) D
① 先看懂图(所有小问都靠它): 这是一个复合状态 C ,里面按顺序放了子状态 A → B :
∘ A :do/count(在 A 内持续执行 count)、exit/I++(离开 A 时执行 I++)。
∘ B :entry/a=0(进入 B 时把 a 置 0)、do/print(在 B 内持续打印)、exit/a++(离开 B 时 a 加 1)。
∘ 从 B 出发 到 简单状态 D 的迁移,标签是 when b=0 [a>5]:when b=0 是事件、[a>5] 是监护条件。
回答 (41) — 为什么是 B(反应型对象): UML 每种图都有固定的"建模对象",背下来即可秒杀:
∘ 类图 → 系统的词汇 (系统里有哪些概念/名词);对象图 → 对象快照 (某时刻各对象的取值);活动图 → 活动流程 (控制流/工作流);
∘ 状态图 → 反应型对象 (对外部事件做出反应、状态随之迁移的对象)。
题干给的是状态图、又强调"动态方面",锁定 B ;A/C/D 正好分别是类图/活动图/对象图的用途,是干扰项。
回答 (42) — 为什么是 B("状态 A 和 B 的所有动作完成"): 要问"什么时候 C 能转移到 D"。看图的路径:必须先做完 A (do/count,离开时 exit/I++),再进入并做完 B (entry/a=0→do/print→离开时 exit/a++);等 A、B 都结束 ,此时 when b=0 发生且 [a>5] 成立,B→D 的迁移才触发。所以答案是"A 和 B 的所有动作完成 "→ B 。
∘ 为何不是 A/C/D:它们都只提到"状态 A 完成/退出",但图里 A 后面还排着 B ,A 完成 ≠ 整条路径完成,转换条件尚不具备 → 全错。
回答 (43) — 为什么不正确的叙述是 D("状态由事件触发"): 逐项辨析:
∘ A 正确 :动作既可写在状态内部 (entry/do/exit),也可写在转换 上(迁移后的效果)。图里 do/count 是前者。
∘ B 正确 :这正是状态机语义——事件触发且无监护条件约束时,对象离开当前状态,正在执行的 do 动作被中断、终止 (所以 A 的 count 会被打断)。
∘ C 正确 :when(...) 是变化事件 (某布尔表达式由假变真时触发,如 when b=0);与它相对的是时间事件 (after(5s)、at(...))。
∘ D 是错的(本题选它) :事件才是"对象可感知到的发生",正确说法是"状态转移由事件触发 ";说成"状态由事件触发"把因果关系说反了 → 不正确的是 D 。
⚠ 争议提醒:网络两个解析源(CSDN)给出参考答案均为 BBD 。但若咬文嚼字,C 把 when(b=5) 说成"时间 事件"也不严谨(它是变化 事件);只是命题人显然按"when 属于事件类、D 的因果表述明显错"来定键。考场以官方键 D 为准 。
Q44–47 设计模式:命令 Command(含原图)
股票交易中,股票代理(Broker)根据客户发出的股票操作指示进行股票的买卖,设计如下所示类图。该设计采用(44)模式将一个请求封装为一个对象,从而可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。其中,(45)声明执行操作的接口。该模式属于(46)模式,该模式适用于(47)。
2021 上 · 命令模式类图(原图)
(44) A. 命令Command B. 观察者Observer C. 状态State D. 中介者Mediator
(45) A. Operation B. SellOperation/BuyOperation/ViewOperation C. Broker D. Stock
(46) A. 结构类型 B. 结构型对象 C. 创建类型 D. 行为型对象
(47) A. 一个对象必须通知其他对象… B. 抽象出待执行的动作以参数化某对象 C. 一个对象的行为决定于其状态… D. 一个对象引用其他很多对象…
(44) A (45) A (46) D (47) B 。
〖第 1 步:先用"点外卖"搞懂命令模式〗
你想吃外卖,但你不会自己冲进厨房炒菜 。你的做法是"下一张订单 "交给骑手,骑手把订单送到厨房,厨房照单炒菜。这里发生了三件事:
∘ 你把"炒个宫保鸡丁"这个请求 ,封装成了一张可传递的订单对象 ;
∘ 你和厨房之间解耦 了——你不用知道厨房怎么炒、用几号锅;
∘ 订单可以排队 (一单单来)、可以记录 (订单列表)、可以撤销/退单 。
命令模式就是把"请求"变成"订单对象" 。题目里"把一个请求封装为一个对象……可撤销"就是"下订单"的软件版。
〖第 2 步:把类图的每个角色对号入座(配原图看)〗
① Operation(最上面的抽象类,含 +execute())= 命令接口 :相当于"空白订单的模板 ",规定所有订单都必须有一个 execute()(执行)动作。
② SellOperation / BuyOperation / ViewOperation(中间三个子类)= 具体命令 :相当于"各种具体的订单 "(卖出单、买入单、查看单)。它们都继承了 Operation,各自实现 execute();每个还带一个 -stock:Stock 字段,表示"这单要发给哪个股票部门"。
③ Broker(下方中间,含 +execute() 和 operator.execute())= 调用者 Invoker :相当于"发单的骑手/前台 "。它手里只拿着一张抽象的订单 (operator:Operation),Broker() 构造时把订单交给它;它自己不炒菜,只是在 execute() 里喊一声 operator.execute()——"去,把这单执行掉 "。
④ Stock(左上方)= 接收者 Receiver :这才是"真正干活的厨房 ",真正执行买卖股票的动作。
⑤ StockDemo(左下方)= 客户端 Client :负责"点单+组装"——创建好各种命令对象,塞给 Broker。
一句话看懂类图: Broker(发单)拿着抽象的 Operation(订单),Operation 的子类(具体订单)去调用 Stock(厨房)干活。 发单者和干活者被隔开了。
〖图里每条线/符号到底啥意思(重点!)〗
① 三个"空心三角箭头 "(SellOperation、BuyOperation、ViewOperation → Operation)= 泛化(继承) :
三角是空心 、箭头指向父类 (Operation)。这三句话的意思就是"SellOperation 是一种 Operation""BuyOperation 是一种 Operation"……即它们继承 了命令接口、都要实现 execute()。
记忆:空心头(三角)=继承(泛化);实线=类图泛化、虚线=实现接口。
② 从 Broker 扇形出去的三条"普通箭头 "(Broker → 三个具体命令)= 关联(association) :
表示 Broker 认识/持有 这些命令对象(它就是拿着 operator:Operation 这个引用)。注意箭头方向 :指向它"要用的对象",即"Broker 知道 Operation"。
③ 每个命令类里的 -stock:Stock(前面的短横线)= 属性(attribute),也体现一条关联 :
- 表示私有(private) 成员;stock:Stock 表示"这个命令持有一个 Stock 对象",也就是"具体订单最终要交给哪个部门(Stock)去执行"——这是命令 → 接收者 的关系。
④ StockDemo → Stock、StockDemo → Broker 两条箭头 = 关联/依赖 :
客户端 StockDemo 要"用"到 Stock(干活对象)和 Broker(发单对象),所以它指向这两者。一个类"用到"另一个类,画条箭头指过去 即可(弱关系用依赖,长期持有用关联)。
⑤ 右边那张"带折角的纸 "(便签,写着 operator.execute())= 注释(note) :
折角纸是 UML 的注释框 ,不是类,只是在旁边写句说明。它用虚线 连到 Broker,虚线端点那个实心小圆点=注释锚点 ,表示"这条注释是写给 Broker 的"。
⑥ 类名框里那个小圆圈(Operation 右上角) :只是原图的图形/水印残留,不是 UML 符号 ,忽略即可;
Operation 是抽象类 (方法体只声明不实现),UML 规范里抽象类名应用斜体 表示。
一张图总结线型: 空心三角=继承;普通箭头=关联/依赖(谁用谁);实心菱=组合、空心菱=聚合;虚三角=实现接口;折角纸+虚线=注释。
〖第 3 步:逐问详解〗
(44) 是什么模式 → A 命令(Command): 题干里有一串"命令模式官方定义句 ":将请求封装为对象、用不同请求对客户参数化、请求排队、记录日志、可撤销 ——把这几个词凑齐,就是命令模式,选 A。
逐项排除: B 观察者=一变全通知(跟"封装请求"无关);C 状态=对象行为随状态改变;D 中介者=封装对象间的复杂交互 (它管的是"谁和谁通信",不是"把请求封装成对象")。
(45) 谁声明执行操作的接口 → A Operation: 题目问的是"谁规定了这个动作怎么执行 "。看图,最上面那个抽象类 Operation 里写着 +execute()——接口(方法声明)就写在它身上 。
逐项排除: B(Sell/Buy/ViewOperation)是"具体实现"接口的子类,属于"实现类 "不是"声明者";C(Broker)是调用者 ;D(Stock)是接收者 。只有 A 是"声明接口"的那一个 → 选 A。
(46) 属于哪种模式 → D 行为型对象: 设计模式分三大类:创建型 (管"怎么造对象")、结构型 (管"类/对象怎么拼装")、行为型 (管"对象之间怎么协作、职责怎么分配")。命令模式关心"请求怎么在对象间传递与执行"→ 属于 行为型 ;它是靠"组合 (Broker 持有 Operation 引用)"而不是靠"继承"来实现的,所以是"对象 模式"。合起来 = 行为型对象 ,选 D。
小知识: "类 模式"靠继承(只有 4 个:工厂方法、适配器-类、解释器、模板方法),其余都是"对象"模式;命令模式用组合,故是对象模式。
(47) 该模式适用于 → B"抽象出待执行的动作以参数化某对象": 问的是"命令模式什么时候用 "。它的用途就是"把要做的事抽象成一个对象(订单),方便拿去当参数传递、排队、记录、撤销 ",正是 B。
逐项排除: A"一个对象必须通知其他对象"= 观察者的场景;C"一个对象的行为决定于其状态"= 状态的场景;D"一个对象引用其他很多对象"= 中介者/外观的场景。只有 B 讲的是"把动作抽象成对象 ",选 B。
〖口诀收尾〗 见"封装请求 / 可撤销 / 排队 / 日志 " → 命令模式;它 = 行为型对象 模式;接口声明在抽象类(Operation) ,调用者在 Broker,干活的在 Stock。
2021 下(11月)上午 · Q37–47
Q37 OOD 主要活动
面向对象设计时包含的主要活动是( )。
A. 认定对象、组织对象、描述对象间相互作用、确定对象的操作
B. 认定对象、定义属性、组织对象、确定对象的操作
C. 识别类及对象、确定对象的操作、描述对象间相互作用、识别关系
D. 识别类及对象、定义属性、定义服务、识别关系、识别包
答案 D 。
小白版: 这一问和 2021 上 Q37 是"姊妹题 "——那个考 OOA(分析) ,这个考 OOD(设计) 。两者顺序要分开记:
∘ OOA(分析) :认定对象 → 组织对象 → 描述对象间相互作用 → 确定对象的操作(更粗,回答"有哪些对象、干什么")。
∘ OOD(设计) :识别类及对象 → 定义属性 → 定义服务 → 识别关系 → 识别包 (更细,回答"类怎么落成属性、方法、关系、怎么分包")。
D 完整含"定义属性/定义服务/识别包",正是设计阶段的动作 → 选 D。
口诀: 带"包 / 属性 / 服务 "的是 OOD 设计 ;只讲"认定 / 组织 / 描述 "的是 OOA 分析。
Q38 设计原则
在面向对象设计时,如果重用了包中的一个类,那么就要重用包中的所有类,这属于( )原则。
A. 接口分离 B. 开放-封闭 C. 共同封闭 D. 共同重用
答案 D(共同重用 CRP) 。
小白版: "重用了包里的一个类,就得重用这个包里的所有类 "——意思是这个包里的类是"成套打包 "的,要么整体拿去用,要么别用。所以叫"共同重用 "。
和"共同封闭"别搞混(高频混淆点):
∘ 共同重用 CRP :看关键词"重用其一 → 重用全部 ";
∘ 共同封闭 CCP :看关键词"变化 会同时影响整包里的类"。
记忆: 题里出现"重用"就选共同重用,出现"变化"就选共同封闭 。本题明确说"重用 ",故选 D。
Q39–40 类图关系:关联 / 聚合
某电商系统在采用面向对象方法进行设计时,识别出网店、商品、购物车、订单、买家、库存、支付等类。其中,购物车与商品之间适合采用(39)关系,网店与商品之间适合采用(40)关系。
(39) A. 关联 B. 依赖 C. 组合 D. 聚合 | (40) A. 依赖 B. 关联 C. 组合 D. 聚合
(39) A (40) D 。
小白版:先分清 UML 类图的"关系强弱" (从弱到强):依赖 < 关联 < 聚合 < 组合 。
∘ 依赖 :只是"用一下"(方法参数、临时变量),最弱;
∘ 关联 :两个类"长期认识",对象之间互相持有引用 ,但彼此独立、没有整体部分之分;
∘ 聚合 :整体-部分 ,但部分能独立存在 (空心菱形);
∘ 组合 :整体-部分 ,且部分离不开整体 (实心菱形,同生共死)。
(39) 购物车 ↔ 商品 = 关联(A): 购物车里"存放"着若干商品的引用。商品不是购物车的组成部分,删掉购物车商品照样独立存在,它俩只是"认识/引用"关系 → 关联 。
(40) 网店 ↔ 商品 = 聚合(D): 网店"拥有/包含"商品,是整体-部分 ;但商品下架后仍可独立存在(还能进别的店),不是"同生共死" → 满足"整体部分 + 部分能独立" → 聚合 。
判关系三步法: ① 是否"整体-部分"?否→依赖/关联(再看是不是只是临时用一下:是→依赖,否→关联)② 是"整体-部分",再看部分能否独立:能→聚合 ,不能→组合 。
Q41–43 状态图三要素(含原图)
某软件系统限定:用户登录失败的次数不能超过 3 次。采用如下 UML 状态图对用户登录状态建模,假设活动状态是 Logging in,那么当 Valid Entry 发生时(41)。其中,[tries<3] 和 tries++ 分别为(42)和(43)。
2021 下 · 用户登录状态图(原图)
(41) A. 保持在 Logging in 状态 B. 若[tries<3]为 true,则 Logged in 变为下一个活动状态 C. Logged in 立刻变为下一个活动状态 D. 若 tries=3 为 true,则 Logging Denied 变为下一个活动状态
(42) A. 状态 B. 转换 C. 监护条件 D. 转换后效果 | (43) A. 状态 B. 转换 C. 转换后效果 D. 监护条件
(41) B (42) C(监护条件) (43) C(转换后效果) 。
先看懂这张图(原图三条转换): 起点→Logging in (entry/tries=0)。从 Logging in 出去有三条线:
∘ Invalid Entry / tries++ → 回到自己(自环,登录失败一次、计数 +1);
∘ Valid Entry [tries<3] → Logged in (登录成功);
∘ tries=3 → Logging Denied (错满 3 次被拒)。
(41) 为什么是 B: 题干问"当 Valid Entry 发生时 "。看图的对应转换:Valid Entry [tries<3] 指向 Logged in ——即"发生 Valid Entry,且监护条件 [tries<3] 为真"时,Logged in 成为下一个活动状态 → 选 B 。
∘ 排除:A"保持在 Logging in"错(那是 Invalid Entry 的行为);C"立刻变为"错(漏了要先满足监护条件 [tries<3]);D"tries=3 则 Logging Denied"——tries=3 是另一条 转换(且 D 的措辞把触发事件与状态说混了)。
状态图"四件套"通用读法: 一条转换线上从前往后是——触发事件 [监护条件] / 动作 ,即 事件[条件]/动作:
∘ 触发事件 :什么发生了才走这条线(Valid Entry、tries=3)——被动"导火索";
∘ 监护条件 :写成方括号 [tries<3],布尔判断,为真才放行;
∘ 动作/转换后效果 :写在斜杠 / 后,转换发生时执行(tries++)。
(42) [tries<3]: 用方括号包着 → 是监护条件 (C)。
(43) tries++: 写在转换的动作位置、转换发生时才执行 → 转换后效果 (C)。注意它不是状态 (状态是有名字的框,如 Logging in)。
一句话记态图三要素: 无括号=事件;方括号=监护条件;斜杠后=动作(转换后效果) 。
Q44–46 设计模式:中介者 Mediator(含原图)
不同组访问数据的权限不同,每个用户可以是多个组成员。现要求在用户和组之间设计映射,将关系由映射维护,得到如下类图。该设计采用(44)模式,用一个对象封装系列的对象交互;使用户对象和组对象不需要显式相互引用。该模式属于(45)模式,该模式适用(46)。
2021 下 · 中介者模式类图(原图)
(44) A. 状态 B. 策略 C. 解释器 D. 中介者 | (45) A. 创建型类 B. 创建型对象 C. 行为型对象 D. 行为型类
(44) D (45) C 。
先看懂这张类图: 用户(User)和组(Group)之间原本要"多对多 "互相引用(每个用户记着自己属于哪些组、每个组记着有哪些用户,关系爆炸)。现在引入一个映射/中介者 对象,由它统一维护"用户↔组"的对应关系,User 和 Group 不再直接互相认识 。
(44) 为什么是 D 中介者: 题干原话"用一个对象封装一系列的对象交互,使对象不需要显式相互引用 "——这就是中介者模式的定义句。见到"封装交互、减少对象间直接引用、多对多变一对多 "直接选 Mediator。
易混(各模式定义句): 状态=行为随状态改变;策略=多种可互换算法;解释器=定义文法+解释句子。
(45) 为什么是 C 行为型对象: 中介者管的是"对象之间如何协作交互"→ 行为型 ;它靠"组合 (持有中介者引用)"实现而非继承 → 对象 模式。合起来"行为型对象"。
Q47 设计模式:策略 Strategy
在设计某购物中心的收银软件系统时,要求能够支持不同时期推出打折、返利、满减等不同促销活动,则适合采用( )模式。
A. 策略 B. 访问者 C. 观察者 D. 中介者
答案 A(策略 Strategy) 。
小白版: 打折、返利、满减……每一种促销是一套"算法 ",它们地位平等、可以互相替换,而且后台随时可能加一种新的(比如"第二件半价")。如果全写成 if-else 会越来越乱。策略模式把它们各自封成一个"策略类",运行时可随时切换 。
识别关键词: "多种可互换的算法/规则 ""不同时期采用不同……""可灵活切换" → 选策略 。
和相近模式区分: 访问者=对结构中的元素做新操作;观察者=一改全通知;中介者=封装对象间复杂交互。本题"多套算法可换"只有策略对得上。
2022 上(5月)上午 · Q16–19、Q41–47
Q16 动态绑定
在运行时将调用和响应调用所需执行的代码加以结合的机制是( )。
A. 强类型 B. 弱类型 C. 静态绑定 D. 动态绑定
答案 D(动态绑定) 。
小白版:"绑定"就是"把一次方法调用和真正要执行的那段代码对应起来 "。
∘ 编译时 就确定好调用哪段代码 → 静态绑定 (早期绑定);
∘ 运行时 才根据"对象到底是什么类型"决定调用哪段代码 → 动态绑定 (晚期绑定)。
为什么需要动态绑定: 父类引用 Animal a,编译时不知道 a 到底装的是 Bird 还是 Cat,只有运行到 a.move() 那一刻,才看它实际指向谁,进而调用对应实现——这正是多态的实现机制。
排除: 强/弱类型说的是"类型检查严不严",跟绑定时机无关。题干"运行时 结合"→ 动态绑定。
Q17 设计原则
进行面向对象系统设计时,在包的依赖关系图中不允许存在环,这属于( )原则。
A. 单一责任 B. 无环依赖 C. 依赖倒置 D. 里氏替换
答案 B(无环依赖 ADP) 。
小白版: 把系统按功能分成一个个"包"(package),包之间会有依赖(A 用到 B)。如果依赖关系绕成一个环 (A→B→C→A),那这三个包就"绑死"了:想单独测试/复用/理解其中任何一个,都必须把整圈一起拉进来,还容易牵一发动全身。
所以这条原则要求:包的依赖关系图中不允许出现环 ,依赖要成一棵"有向无环图" → 叫无环依赖 。
关键词: "包的依赖图 / 不允许有环 " → 无环依赖。其余选项(单一责任/依赖倒置/里氏替换)都不涉及"环"。
Q18–19 OOA 第一步 / 面向对象实现
面向对象分析的第一项活动是(18);面向对象程序设计语言为面向对象(19)。
(18) A. 组织对象 B. 描述对象间相互作用 C. 认定对象 D. 确定对象的操作 | (19) A. 用例设计 B. 分析 C. 需求分析 D. 实现
(18) C (19) D 。
(18) 为什么是 C 认定对象: 面向对象分析的第一件事 就是"从需求里认出有哪些对象 "——最常用的办法是"找名词 "(把需求描述里的名词圈出来,多半就是候选对象/类)。B"描述对象间相互作用"、A"组织对象"、D"确定对象的操作"都是认定对象之后 才做的。→ 选 C。
(19) 为什么是 D 实现: 面向对象的整个流程是 分析(OOA)→ 设计(OOD)→ 编程实现(OOP) 。而"面向对象程序设计语言"(Java/C++)是拿来写代码实现 的,处在最后一环 → 选"实现"。
串联记忆: OOA 找对象 → OOD 设计类结构 → OOP 用语言实现。
Q41–43 活动图 / 构件图(含原图)
UML 活动图用于建模(41)。以下活动图中,活动 A1 之后,可能的活动执行序列顺序是(42)。UML 构件图展现了一组构件之间的组织和依赖,专注于系统的静态(43)图。
2022 下(11月) · 活动图(原图,用于本题型)
(41) A. 系统在它的周边环境的语境中所提供的外部可见服务 B. 某一时刻一组对象以及它们之间的关系 C. 系统内从一个活动到另一个活动的流程 D. 对象的生命周期中某个条件或者状态
(42) A. A2、A3、A4 和 A5 B. A3、A4 和 A5,或 A2、A4 或 A5 C. A2、A4 和 A5 D. A2 或 A3、A4 和 A5
(43) A. 关联 B. 实现 C. 结构 D. 行为
(41) C (42) D (43) B 。
(41) 为什么是 C: UML 每种图"建模什么"要背熟(上午反复考):
∘ 活动图 → 系统内"活动到活动"的处理流程 (控制流/工作流,C 对);
∘ A"外部可见服务"是用例图 ;B"某时刻对象及关系"是对象图 ;D"对象生命周期状态"是状态图 。
所以选 C。
(42) 为什么是 D(A2 或 A3、A4 和 A5): 先认清图里两个关键符号:
∘ 菱形(◇) = 判断/分叉(choice),"二选一、互斥" ——A1 出来后走菱形,要么走 A2、要么走 A3 ,不会两个都走;
∘ 粗黑竖条 = 并发(fork/join),"同时进行" ——A3 出来后 fork,A4 和 A5 并行执行 ,再 join 汇合到终结点。
于是 A1 之后只有两条可能路径:① 走上面 → A2 →(直接到终点) ;② 走下面 → A3 → A4 ∥ A5 → 终点 。合起来 = "A2 或 A3、A4 和 A5 ",即 D 。
逐项排除: A 把菱形当"全都做"(错,菱形是二选一);C 漏了 A3 那条分支、又把 A2 和 A4/A5 并列(错);B 说"A2、A4 或 A5"(错,A2 那条路后面根本没有 A4/A5)。
(43) 为什么是 B 实现: 构件图(Component Diagram)展示"一组构件之间的组织和依赖",它描述系统的静态实现视图 (构件=可部署的软件部件,看它们如何组装实现系统)→ 官方答案为"实现 "。
易错点: "结构"(C)是干扰项——构件图确实是静态图,但 UML 约定它专注的是"实现 "这一静态视角,故填 B。
图族一句话记: 类图=词汇、对象图=快照、用例图=外部可见服务、活动图=流程、状态图=对象的生命周期条件/状态、构件图=静态实现 。
Q44–46 设计模式:责任链(含原图)
某系统中,不同级别的日志信息记录方式不同,每个级别的日志处理对象根据信息级别高低采用不同方式记录:检查消息级别,达到则记录否则传递给下一个日志处理对象。针对此需求设计如下类图。该设计采用(44)模式使多个前后连接的对象都有机会处理请求。该模式属于(45)模式,适用于(46)。
2022 下(11月) · 责任链模式类图(原图,用于本题型)
(44) A. 责任链 B. 策略 C. 过滤器 D. 备忘录 | (45) A. 行为型类 B. 行为型对象 C. 结构型类 D. 结构型对象
(46) A. 不同标准过滤一组对象… B. 可处理一个请求的对象集合应被动态指定 C. 必须保存对象某时刻状态… D. 一个类定义了多种行为并以多个条件语句出现
(44) A (45) B (46) B 。
(44) 为什么是 A 责任链: 题干原话"检查消息级别,达到则记录,否则传递给下一个处理对象 "——每个处理者只管自己那部分、处理不了就甩给下一个,形成一条"链" → 责任链模式 。
(45) 为什么是 B 行为型对象: 它管的是"请求在多个处理者之间怎么传递"→ 行为型 ;靠持有下一个处理者的"引用(组合) "串成链 → 对象 模式。合起来"行为型对象"。
(46) 为什么是 B: 问适用场景。B"可处理一个请求的对象集合应被动态指定 "——处理请求的到底是哪几个对象、顺序如何,运行时才定下来,正是责任链的用途。A 是过滤器/组合的场景,C 是备忘录的场景,D 是状态/策略的场景。
Q47 设计模式:适配器 Adapter
驱动新能源汽车的发动机时,电能和光能汽车分别采用不同驱动方法,而客户端希望使用统一的驱动方法,需定义一个统一的驱动接口屏蔽不同的驱动方法,该要求适合采用( )模式。
A. 中介者 B. 访问者 C. 观察者 D. 适配器
答案 D(适配器 Adapter) 。
小白版: 现实里"电源转换插头"就是适配器——中国的插头插不进国外插座,中间加个"转接头"就能用。软件里也一样:电能车、光能车各有一套驱动方法(不兼容的接口 ),客户端只想调一个统一的方法。适配器模式就在中间做个"转换层 ",对外暴露统一接口,对内去调各自不同的实现。
识别关键词: "接口不兼容 / 想用统一接口屏蔽不同实现 / 转换 " → 选适配器 。
和相近模式区分: 中介者=封装对象间复杂交互(多对多);访问者=对已有结构加新操作;观察者=状态一变就通知。"统一接口、屏蔽差异"只有适配器对得上。
2022 下(11月)上午 · Q37–47
Q37–38 多态 / 动态绑定
游戏中有野鸭、红头鸭等鸭子,鸭子类负责呱呱叫和游泳方法的实现,显示颜色设计为抽象方法由子类各自具体实现,这一机制称为(37)。当给这些类型的一组不同对象发送同一显示颜色消息时,能实现各自显示不同颜色的结果,这种现象称为(38)。
(37) A. 继承 B. 聚合 C. 组合 D. 多态 | (38) A. 覆盖 B. 重载 C. 动态绑定 D. 多态
(37) A(继承) (38) D(多态) (已核对官方答案键:37A 38D)。
怎么做:(37) 题干问的是"在父类写抽象方法 、由子类各自实现"这一机制 本身——父类把共同部分(呱呱叫、游泳)实现好、把变化部分(显示颜色)留成抽象方法交给子类,这就是继承 (is-a、复用+特化)→ 选 A。
(38) 题干问的是"给一组不同对象发同一消息 、各自产生不同结果 "这一现象 ——同一消息不同响应 = 多态 → 选 D。("动态绑定"是实现多态的手段,属于机制而非现象,是干扰项。)
Q39 认定对象
采用面向对象方法分析时,首先要在应用领域中按自然存在的实体认定对象,即将自然存在的( )作为一个对象。
A. 问题 B. 关系 C. 名词 D. 动词
答案 C(名词) 。
小白版: 做面向对象分析、要"认出有哪些对象"时,有个经典土办法——看需求描述里的"名词" 。因为对象通常对应现实中的实体(人、物、单据……),而这些在句子里都是名词。("动词"一般对应方法/操作,"关系"对应关联,都不是"对象"。)
对应 OOA 第一步: 认定对象(找名词)→ 组织对象 → 描述相互作用 → 确定操作。见 ① 节 OOA/OOD/OOP 。
Q40 设计原则
进行面向对象系统设计时,修改某个类的原因有且只有一个,即一个类只做一种类型的功能,这属于( )原则。
A. 单一责任 B. 开放-封闭 C. 接口分离 D. 依赖倒置
答案 A(单一责任 SRP) 。
小白版: 单一责任原则 = "一个类只干一件事、只有一个被修改的理由 "。比如"报表类"就只管生成报表,别又让它去连数据库、又去管网页——那样任何一处需求变了都得改它,改它的理由就有一堆。一个类只承担一种职责,才能"模块化、易维护"。
识别关键词: "修改的原因有且只有一个 / 只做一种功能 " → 单一责任。
和相近原则区分: 开放-封闭=对扩展开放、对修改关闭;接口分离=别强迫客户依赖不用的方法;依赖倒置=依赖抽象不依赖具体。
Q44 设计模式:责任链(含原图)
日志分级处理、逐级传递处理请求—采用( )模式。
2022 下 · 责任链模式类图(原图)
A. 责任链(Chain of Responsibility) B. 策略 C. 过滤器 D. 备忘录
答案 A(责任链) 。
小白版: "日志分级别,本级处理不了就交给下一级 "——请求沿着一串处理对象依次传递,直到有人处理,这就是责任链 。
识别关键词: "逐级传递 / 处理不了交给下一个 / 多个对象都有机会处理 "。本题与 2022 上 Q44–46 是同一考点,作答理由同那里。
Q47 设计模式:适配器 Adapter
电能和光能汽车采用不同驱动方法,客户端希望使用统一的驱动方法,需定义一个统一的驱动接口屏蔽不同的驱动方法,适合采用( )模式。
A. 中介者 B. 访问者 C. 观察者 D. 适配器
答案 D(适配器 Adapter) 。
小白版: 电能车、光能车"驱动方法不同",客户却想"调一个统一方法"——在中间加个"转换层"把不同接口统一起来,就是适配器 。
识别关键词: "统一接口屏蔽不同实现 / 接口不兼容需转换 "。本题与 2022 上 Q47 是同一考点。
⑧ 下午案例题(原题 + 原图 + 参考答案)
下午第 3 题固定考 UML:读需求 → 补用例名/类名/关系 → 简述某关系含义 。下面每套给完整说明、原图与参考答案。
2020 下 · 试题三:房产信息管理系统(用例图 + 类图)
【说明】 (概述)某房产公司开发的房产信息管理系统:①房产分住宅 House 和 公寓 Cando 两类(泛化);②雇佣房产经纪 Agent 负责销售;③系统用户包括房产经纪和系统管理员 Manager ,需身份验证登录;经纪可录入/查询负责的房产信息,修改需管理员审批授权 ;④管理员可导出、归档、删除房产信息。
图 3-1 用例图(原图)
图 3-2 类图(原图)
【问题1】(7分) 给出图3-1 中 A1~A2 的参与者 名称、U1~U3 的用例 名称,以及 (a)(b) 用例之间的关系 。
【问题2】(6分) 给出图3-2 中 C1~C6 的类名 。
【问题3】(2分) AgentList 进一步阐述 C1 和 C6 的关系,给出其主要属性。
问题1: A1=房产经纪;A2=系统管理员;U1=审批授权;U2=修改房产信息;U3=删除房产信息;(a)=«include» ;(b)=«extend» 。
问题2: C1=Property;C2=House;C3=Cando;C4=User;C5=Manager;C6=Agent。
问题3: AgentList 属性=房产经纪负责该房产的起始时间和终止时间 。
下午 UML 题通用打法(先记住这三步): ① 找参与者 :需求里"和系统打交道的外部角色 "(人/外部系统)→ 房产经纪、系统管理员。② 找用例 :需求里的"动宾短语 "(系统帮用户做什么)→ 审批授权、修改、删除……③ 找类 :需求里的"名词 ",再按题给的图填编号。
问题1 详解: 参与者是 A1、A2:房产经纪(Agent)负责销售、录入查询;系统管理员(Manager)负责审批、导出归档删除。用例看图:U1 挂在"审批授权"上、U2 是"修改房产信息"、U3 是"删除房产信息"。
∘ (a)=include(包含) :指"基本用例每次都必须做的公共步骤 "。经纪要"修改房产信息"前必须先"审批授权",是被包含的必经步骤 → include。
∘ (b)=extend(扩展) :指"可选/有条件的附加分支 "。"删除房产信息"不是每次必做,只有满足条件才发生 → extend。
include vs extend 口诀: 每次都做、被抽出来复用 → include ;可选、条件触发 → extend 。
问题2 详解: 按"名词法"+泛化/关联判断:父类 C1=Property(房产) ,子类 C2=House(住宅) 、C3=Cando(公寓) (三者的空心三角箭头向上指 C1 = 泛化);用户父类 C4=User ,其子类 C5=Manager(管理员) 、C6=Agent(经纪) 。
问题3 详解: C1(Property)和 C6(Agent)之间是多对多关联类 AgentList,它记录"哪个经纪负责哪套房"。关联类的属性 = 这段关系本身要存的信息 = 经纪负责该房产的起止时间 (还可能含佣金等)。
一句话总结做下午 UML 题: 参与者找"人/外部系统"、用例找"动宾短语"、类找"名词"、关系看"箭头形状"。
2021 上 · 试题三:中医医院线上抓药 APP(用例图 + 类图)
【说明】 患者凭医生处方线上抓药、免费送药上门:①注册(扫二维码,提供病历号);②登录;③确认处方(选处方和数量、是否煎制、取药方式;自行取药或送药上门;微信/支付宝支付;支付成功后处方发给药师);④处理处方(药师配药,煎制,设为完成);⑤药品派送(给快递人员发送配送信息);⑥送药上门(快递人员送货,患者出示收货验证码确认)。
图 3-1 用例图(原图)
图 3-2 类图(原图)
【问题1】(7分) 给出图3-1 中 A1~A3 的参与者名称、U1~U4 的用例名称。
【问题2】(5分) 给出图3-2 中 C1~C5 的类名。
【问题3】(3分) 简要解释用例之间的 include、extend 和 generalize 关系的内涵。
问题1: A1=患者;A2=快递人员;A3=药师;U1=确认处方;U2=支付方式;U3=微信;U4=支付宝(U3、U4 可互换)。
问题2: C1=支付方式;C2=微信;C3=支付宝(C2、C3 可互换);C4=处方;C5=药品。
问题3: include =从多个用例提取的公共行为,抽成抽象用例被基本用例(每次必做);extend =基本用例的可选/特殊分支(条件满足才发生);generalize =将多个用例的共性抽象为父用例,子用例继承父用例的结构、行为和关系。
问题1 详解(参与者 & 用例): 先按"人/外部系统"找参与者:A1=患者 (打电话要药、付款、收货)、A2=快递人员 (被通知去送药)、A3=药师 (配药、煎制)。再用例(动宾短语):U1=确认处方 (选处方和数量、取药方式)、U2=支付方式 ,其下 U3、U4 是两种具体支付:U3=微信、U4=支付宝 。
问题2 详解(类图填类名): 看箭头/包含关系:C1=支付方式 (父类),它的两个子类 C2=微信、C3=支付宝 ;C4=处方 (含药品清单)、C5=药品 。
问题3 详解(三种关系的内涵,必背):
∘ include(包含) :把多个用例都要重复执行 的公共行为抽成一个抽象用例,基本用例"包含"它——每次必定执行 ,是"整体的一部分"。例:任何付款都得"验证密码"。
∘ extend(扩展) :基本用例的可选/特殊分支 ,只有满足条件才发生(不是每次都走)。例:"付款"之外可选"用优惠券"。
∘ generalize(泛化) :把多个用例的共性 抽象成父用例,子用例继承 父用例的结构、行为和关系,并可增加/覆盖自己的部分。例:"微信支付""支付宝支付"泛化出"支付"。
三者一句话辨析: include=必经的公共部分;extend=可选的附加分支;generalize=父子继承(共性上提)。
2021 下 · 试题三:吃金币迷宫游戏(用例图 + 类图)
【说明】 迷宫中机器人分小精灵 PacMan 和 幽灵 Ghost ;机器人有两种传感器:前向传感器 FrontSensor 、近距离传感器 ProxiSensor ;每个机器人有计时器 Timer 。用户用编辑器 Editor 编写迷宫文件,导入建立迷宫 Maze 。
用户
建立迷宫
U1
编写迷宫文件
U2
导入迷宫文件
操作机器人
U3
设置计时器
«include»
图 3-1 用例图(按标准答案重绘,专题页原先漏收;不是原卷扫描)
图 3-2 类图(原图)
【问题1】(3分) 给出图3-1 中 U1~U3 所对应的用例名。
【问题2】(4分) 图3-1 中用例 U1~U3 分别与哪个(些)用例之间有关系,是何种关系?
【问题3】(8分) 给出图3-2 中 C1~C8 所对应的类名。
问题1: U1=编写迷宫文件;U2=导入迷宫文件;U3=设置计时器。
问题2: U1、U2 和"建立迷宫"是泛化 关系(建立迷宫用例泛化 U1、U2);U3 和"操作机器人"是包含(include) 关系(操作机器人用例包含 U3)。
问题3: C1=机器人 Robos;C2=计时器 Timer;C3=小精灵 PacMan;C4=幽灵 Ghost(C3、C4 可互换);C5=传感器 Sensor;C6=前向传感器 FrontSensor;C7=近距离传感器 ProxiSensor(C6、C7 可互换);C8=迷宫 Maze。
问题1 详解: 看用例图里 U1~U3 各自的"动宾短语":用户拿编辑器写迷宫文件 →U1=编写迷宫文件 ;把文件导入 生成迷宫→U2=导入迷宫文件 ;给机器人设定计时器 →U3=设置计时器 。
问题2 详解(关系判断,看箭头方向): 用例之间的关系无非 include / extend / 泛化,判断靠"箭头+标签":
∘ U1、U2 与"建立迷宫"之间是泛化 :视图里"建立迷宫"是父用例 ,"编写迷宫文件""导入迷宫文件"是它的两种具体做法 (都是"建立迷宫"的子类型),空心三角箭头从子指向父 → 泛化。
∘ U3 与"操作机器人"之间是包含 include :操作机器人时每次都要用到计时器 ,是被抽出来的公共必做步骤 → include(虚线+«include»)。
问题3 详解(类图,按"名词+泛化"填): 父类 C1=机器人 Robos ,其子类 C3=小精灵 PacMan、C4=幽灵 Ghost ;父类 C5=传感器 Sensor ,子类 C6=前向传感器、C7=近距离传感器 ;此外 C2=计时器 Timer (每个机器人都有一个)、C8=迷宫 Maze 。
规律: 类图里凡是"一个父类被多条空心三角箭头指向"的,那几条就是它的子类;填名时先填父类再填子类。
2022 上 · 试题三:地址簿管理系统(用例图)
【说明】 公司人事部门用地址簿 AddressBook 管理系统管理所有员工的地址记录 PersonAddress (姓名、住址、城市、省份、邮政编码、联系电话等)。管理员为不同部门建立员工地址簿,操作包括创建/打开/修改地址簿,对地址记录进行添加、修改、删除。
图 3-1 用例图(原图)
【问题1】(6分) 给出图3-1 中 U1~U6 所对应的用例名。
【问题2】(5分) 给出类 AddressBook 的主要属性和方法,以及类 PersonAddress 的主要属性。
【问题3】(4分) 简要说明 extends 关系的含义。
问题1: U1=按姓氏字典顺序排序;U2=按邮政编码排序(U1、U2 可互换);U3=创建;U4=修改;U5=GUI;U6=保存。
问题2: PersonAddress 属性=姓名、住址、城市、省份、邮政编码、联系电话;AddressBook 属性=部门名/编号 + 上述地址字段,方法=添加、修改、删除、创建、打开。
问题3: extend 是扩展关系:若一个用例明显混合了两种或以上不同场景(可能发生多种分支),可将其分为一个基本用例和一个或多个扩展用例,使描述更清晰。
问题1 详解: 把 U1~U6 对回"动宾短语":管理员能"按姓氏字典顺序排序 "(U1)、"按邮政编码排序 "(U2)、对地址簿"创建 "(U3)和"修改 "(U4),界面"GUI "(U5)、"保存 "(U6)。排序类的 U1、U2 顺序可互换。
问题2 详解(写属性/方法): 属性就是"这个类要记录哪些数据"、方法就是"这个类要提供哪些功能"。
∘ PersonAddress(个人地址)属性 直接抄需求:姓名、住址、城市、省份、邮政编码、联系电话。
∘ AddressBook(地址簿)属性 是"部门名/编号"(一本簿子对应一个部门)+ 地址字段;方法 对应能做的操作:创建、打开、添加、修改、删除。
问题3 详解(extend 含义,必背): 当一个用例里混了两种以上不同场景/可能的分支 时,把它拆成"一个基本用例 + 若干扩展用例",扩展部分就是"可选、条件触发 "的那种情况,这样用例描述更清晰。例:"打开地址簿"是基本用例,"打印地址簿"是可选扩展。→ 这就是 extend(扩展) 。
2022 下 · 试题三:计量单位换算(用例图 + 类图)
【说明】 某单位换算系统,用户可输入温度、升高/降低温度、显示摄氏/华氏度等,换算规则用不同算法策略实现。
图 3-2 用例图 + 图 3-3 类图(原图)
【问题1】(4分) 给出图3-2 中 U1~U4 所对应的用例名。
【问题2】(8分) 给出图3-3 中 C1~C8 所对应的类名(类名使用图3-1 中标注的词汇)。
【问题3】(3分) 为支持任意计量单位换算,可在图3-3 类图中增加哪种设计模式?简述原因(不超过50字)。
问题1: U1=显示温度;U2=显示华氏度;U3=温度计显示;U4=单位换算。
问题2: C1=TemperatureCovetorDialog;C2~C4=FahrenheitEditBox、CelsiusEditBx、TemperatureBar(顺序可互换);C5~C8=FahrenheitRaise、FahrenheitLower、CelsiusRaise、CelsiusLower(顺序可互换)。
问题3: 策略模式(Strategy) 。原因:多种单位之间不同的换算规则可写成不同的算法策略,这些算法是平等关系,可根据需要选择并灵活切换,把算法实现从业务处理中独立出来。
问题1 详解: 用例(动宾短语):显示温度(U1)、显示华氏度(U2)、温度计显示(U3)、单位换算(U4)。
问题2 详解(用类图里标注的词汇填): C1 是顶层对话框类 TemperatureCovetorDialog ;下一层是显示控件 FahrenheitEditBox(华氏输入框)、CelsiusEditBx(摄氏输入框)、TemperatureBar(温度条) ;再下一层是"升/降温"的具体换算类 FahrenheitRaise、FahrenheitLower、CelsiusRaise、CelsiusLower (同类同层顺序可互换)。
问题3 详解(为什么加策略模式): "任意计量单位换算"意味着换算规则会不断新增/切换 。如果写成一大堆 if-else 判断,每加一种单位都要改老代码。用策略模式 把每种换算规则封成一个独立的"策略类",它们地位平等、可互换 ,客户端运行时挑一个用即可——算法被独立出来、便于扩展 → 所以填策略模式 。
答题模板: "采用策略 模式。因为不同的换算规则可封装成不同的算法策略,彼此平等、可按需选择和切换,将算法与业务处理解耦,便于扩展。"(控制在 50 字内)
2023 上 · 试题三:数字图书馆(用例图 + 类图)
【说明】 数字图书馆面向校内用户提供学术资源(会议论文 ConferencePaper、期刊论文 JournalArticle、学位论文 Thesis)浏览、检索、下载服务;同一会议的论文收录在会议集 Proceeding,同一期的论文收录在一本期刊 Edition;用户分在校学生 Student、教师 Teacher、其他在职人员 Staff。
图 3-1 用例图(原图)
图 3-2 类图(原图)
【问题1】(8分) 给出图3-2 中 C1~C8 对应的类名。
【问题2】(4分) 给出类 C1~C4 的关键属性。
【问题3】(3分) 用户能对关注的数字资源注册他引通知,若资源的他引次数变化则及时通知用户。可在图3-2 类图中增加哪种设计模式?150字内解释原因。
问题1: C1=Resource;C2=ConferencePaper;C3=JournalArticle;C4=Thesis;C5=User;C6=Student;C7=Teacher;C8=Staff(C6~C8 顺序可互换)。
问题2: C1=题名、作者、发表时间、来源、被引次数、下载次数;C2=会议名称、召开时间、召开地点;C3=期刊名称、出版月份、期号、主办单位;C4=学位类别、毕业学校、专业、指导教师。
问题3: 观察者模式(Observer) 。原因:当一个对象状态发生改变时,所有依赖它的对象都得到通知并被自动更新,符合"资源他引次数变化便通知所有关注该资源的用户"。
问题1 详解: 先找父类:C1=Resource(资源) 是总的父类;三种具体资源是它的子类——C2=ConferencePaper(会议论文)、C3=JournalArticle(期刊论文)、C4=Thesis(学位论文) 。用户父类 C5=User ,子类 C6=Student(学生)、C7=Teacher(教师)、C8=Staff(其他在职人员) 。凡是被多条空心三角箭头指着的类就是父类。
问题2 详解(写关键属性): 属性就是"该类要记录的数据字段",从需求里逐字摘:
∘ Resource (所有资源共有):题名、作者、发表时间、来源、被引次数、下载次数;
∘ ConferencePaper :会议名称、召开时间、召开地点;
∘ JournalArticle :期刊名称、出版月份、期号、主办单位;
∘ Thesis :学位类别、毕业学校、专业、指导教师。
问题3 详解(为什么加观察者): 需求是"用户关注 某资源,一旦该资源他引次数变化 就自动通知 所有关注它的用户"。这正是观察者模式 的定义:被观察对象(资源)状态一变,就自动通知所有依赖/订阅它的观察者(用户)。
答题模板: "采用观察者 模式。因为一个对象(资源)状态改变时,需要自动通知并更新所有依赖它的对象(关注用户),符合一对多的通知机制。"(150 字内)
设计模式题(下午第 5/6 题,选一)
2020 下 · 试题六 中介者 Mediator(Java 填空)
在线支付:整合不同电商平台的支付接口,客户在不同平台购物不需关心具体支付接口,采用中介者 模式。
图 6-1 类图(原图)
模式思想: 客户要对接很多电商平台的支付接口(Amazon、淘宝……),如果客户直接和每个平台"点对点"打交道,代码会到处是 if(平台==...)。中介者模式设一个"总机"对象,客户只跟总机打交道,由总机再去联系各平台——把"多对多"变成"一对多" 。
怎么识别: 题干见"整合不同接口 / 客户不需关心具体实现 / 用一个对象封装交互 " → 中介者。
类图与填空思路: 类图里有两层——抽象中介者 WebServiceMediator 声明了 void setAmazon(WebService)、setTaobao(WebService) 等方法(登记各平台);具体 WebService 都持有一个 protected WebServiceMediator mediator; 成员(这就是"中介者引用",是中介者模式的标志字段 ),并向它注册自己。
∘ 填 SetMediator(...):在构造/初始化里把中介者对象存进本对象的 mediator 字段;
∘ 各处调用统一走 mediator.xxx(...),而不是直接 new 具体平台。
答题窍门: Java 填空题见到"protected XXX mediator;"这个字段,就往"给字段赋值/通过它转发调用"方向填。
2021 上 · 试题六 组合 Composite(Java 填空)
层叠菜单:包含菜单项或子菜单,采用组合(composite) 模式。
图 6-2 类图(原图)
模式思想: 菜单里既有"单个菜单项"(MenuItem),也有"子菜单"(Menu),而子菜单里又能再放菜单项……这种"整体和部分可以一视同仁、层层嵌套 "的结构就是组合模式(树形结构)。
怎么识别: 题干见"包含菜单项或子菜单 / 部分-整体 / 树形/递归结构 " → 组合 Composite。
类图结构: 抽象父类 MenuComponent 是"统一的接口",MenuItem 和 Menu 都继承它;Menu 里还放了一个子节点集合 (用来装 MenuItem/Menu),从而支持无限嵌套。
逐空思路(Java):
∘ (1) protected :Menu 里的子节点容器字段用 protected 修饰,便于子类访问;
∘ (2) abstract boolean addMenuElement(MenuComponent element) :父类 MenuComponent 里声明的"添加子元素"抽象方法;
∘ (3) abstract List<MenuComponent> getElement() :声明"取子元素列表"的抽象方法(List<MenuComponent>=装"组件"的集合,体现递归);
∘ (4) List<MenuComponent> elementList :Menu 里存放子节点的集合字段;
∘ (5) mainMenu.addMenuElement(subMenu) :把子菜单加入主菜单,即"整体里装部分"。
口诀: 看到"父类定义统一接口 + 子节点里又存同类型集合" = 组合模式。
2022 上 · 试题五 备忘录 Memento(C++ 填空)
用备忘录 模式提供取消/恢复:Memento 保存状态,Originator 创建并在 Memento 中存状态,Caretaker 恢复状态。
图 5-1 类图(原图)
模式思想: 想在某个时刻"存个档",以后能"读档"恢复——备忘录模式(像游戏的 save/load)。三个角色:发起人 Originator (主角,能产生和恢复自己的状态)、备忘录 Memento (存状态快照的小盒子)、管理者 Caretaker (保管一堆备忘录,但不偷看里面内容)。
怎么识别: 题干见"取消/撤销/恢复、保存某时刻状态、存档 " → 备忘录 Memento。
逐空思路(C++):
∘ (1) return new Memento(state); :Originator 的"创建备忘录"方法里,把当前状态 state 包成一个新 Memento 返回;
∘ (2) Memento.getState(); :恢复时从备忘录里把存的状态取回来;
∘ (3) void add(Memento state) :Caretaker 保存一个备忘录(存进列表);
∘ (4) Memento get(int index) :Caretaker 按序号取回某个备忘录;
∘ (5)(6) :填充"接收/保存的 Memento 实例"(如 Memento memento; 或列表元素赋值)。
口诀: Originator 会 createMemento() 和 restore();Caretaker 负责"存起来/取出来",但只当"仓库管理员",不碰内容。
2021 下 · 试题六 享元 Flyweight(Java 填空)
网络围棋程序用享元 模式减少对象数量、降低内存:棋子分黑/白,位置对象独立。
图 6-1 类图(原图)
模式思想: 网络围棋要摆很多棋子。如果每个棋子都 new 一个对象,内存会被撑爆。但其实"黑子""白子"长得都一样,不同的只是"位置" 。享元模式把对象拆成:可共享的内在状态 (棋子的颜色/形状,全局只有黑、白两个对象)+ 不可共享的外在状态 (落在哪个坐标,每次单独传)。从而大幅减少对象数量、省内存 。
怎么识别: 题干见"大量相似对象 / 减少对象数量 / 降低内存 / 共享 " → 享元 Flyweight。
填空思路(Java): 抽象类 Piece 定义统一接口,声明 abstract void draw();;子类 BlackPiece、WhitePiece 各自实现 draw()。位置信息作为参数传进 draw(位置),而不是存进棋子对象里 ——这样黑白两枚棋子对象就能被所有位置复用。
口诀: "能共享的(颜色/字形)放对象里,会变的(坐标)当参数传" = 享元。
2022 下 · 试题五/六 外观 Facade(C++/Java 填空)
就医流程:患者与挂号/门诊/取药等子系统交互,设接待员(Facade) 代患者完成,采用外观 模式。
图 6-1 类图(原图)
模式思想: 看病要挂号、看诊、取药,跑好几个窗口很麻烦。外观(门面)模式设一个"接待员"(Facade),病人只跟接待员说一句,接待员在内部替他把各子系统按顺序跑一遍。对外只暴露一个简单的统一入口 ,隐藏内部一堆子系统的复杂调用。
怎么识别: 题干见"提供一个统一的高层接口 / 简化子系统调用 / 客户只跟门面打交道 " → 外观 Facade。
逐空思路(C++):
∘ (1) virtual string getName() = 0; :抽象基类里声明纯虚函数(=0 表示纯虚、无实现,须由子类实现);
∘ (2) virtual void dispose(Patient * patient) = 0; :子系统统一的纯虚接口;
∘ (3) new ConcretePatient("name") :创建具体对象(门面内部去 new 具体病人、去调具体子系统)。
类图结构: Facade 持有各个子系统(挂号 Registry、医生 Doctor、药房 Pharmacy)的引用,对外只给一个 dispose() 方法,内部依次调用 它们。
口诀: "一个门面挡在前面,内部乱成一团对外只给一个口" = 外观模式。
本专题速记总收
① 面向对象 = 对象 + 分类 + 继承 + 消息通信 ;对象 = 属性+方法+ID;消息异步 。
② 覆盖=子类重写父类(同名同参);重载=同类同名不同参。动态绑定=运行时 (多态);静态绑定=编译时。
③ 多态4类:参数/包含/过载/强制 ;过载多态=同一名字不同上下文含义。
④ 类图强弱:依赖 < 关联 < 聚合 < 组合;(泛化/实现另算)。
⑤ 图记:三角都空心 (泛化实线、实现虚线);实心菱=组合(同生共死)、空心菱=聚合(可分离) 。
⑥ 用例:include 公共必做(基本→公共);extend 可选分支(扩展→基本);generalize 子→父。
⑦ 设计原则信号:单一责任=只一种功能;接口分离=不强迫客户依赖不用的方法;共同重用=重用成组;共同封闭=变化 影响整包;无环依赖=包图无环;依赖倒置=依赖抽象。
⑧ 设计模式:创建5 / 结构7 / 行为11 ;类模式仅4个 (工厂方法、适配器-类、解释器、模板方法),其余为对象模式。
⑨ 高频识别信号:转换接口=Adapter;树形目录=Composite;多方案切换=Strategy;传递职责=责任链;不直接引用=Mediator;状态变成类=State;日志可撤销=Command;游戏存档=Memento;联动通知=Observer;对外统一接口=Facade;汉字编码=Flyweight;框架=Template Method。
⑩ 下午第3题必答:参与者=外部角色、用例=动宾短语、类=名词 ,先扫需求再对号入座。
↑