# 第4章 类图与对象图 > **考试重要度**:★★★★★ > **核心内容**:类与对象的识别、六大类关系、抽象类与接口、边界类/控制类/实体类 --- ## 📢 从生活中理解类和对象 💬 **类 = 模板,对象 = 具体的东西。** | 概念 | 生活例子 | 代码例子 | |------|----------|----------| | **类** | "汽车"这个类别 | `class Car` | | **对象** | 你家楼下停的那辆红色宝马 | `Car myCar = new Car()` | | **属性** | 颜色、车牌号、排量 | `color`, `plateNumber` | | **操作** | 启动、加速、刹车 | `start()`, `accelerate()` | > 例:银行的"账户"类有属性(姓名、密码、余额)和操作(查询余额、存款、取款)。张三的账户就是一个具体对象,余额是5000元。 --- ## 💡 一、类的三格表示法 ``` ┌──────────────────────┐ │ 类名 │ ← 第一格:类名 ├──────────────────────┤ │ -name: String │ ← 第二格:属性 │ -age: int │ │ +count: int │ ├──────────────────────┤ │ +getName(): String │ ← 第三格:操作(方法) │ +setAge(a: int) │ └──────────────────────┘ ``` ### 属性语法 ``` [可见性] 属性名 [:类型] [=初始值] [{约束}] ``` ### 可见性符号 | 符号 | 名称 | 含义 | |------|------|------| | `+` | Public(公有) | 谁都能访问 | | `-` | Private(私有) | 只能类内部访问 | | `#` | Protected(受保护) | 类内部+子类能访问 | --- ## ✍️ 边学边练(一) **题目**:银行账户类Account有属性:账号(私有)、密码(私有)、余额(私有)、利率(公有)。请用UML类图的三格表示法写出。 **答案:** ``` ┌──────────────────────┐ │ Account │ ├──────────────────────┤ │ -accountNo: String │ │ -password: String │ │ -balance: double │ │ +interestRate: float│ ├──────────────────────┤ │ +getBalance():double│ │ +deposit(amt) │ │ +withdraw(amt) │ └──────────────────────┘ ``` --- ## 💡 二、类之间的六大关系(重中之重!必考!) ### 1. 关联关系(Association)—— "认识/拥有" > **含义**:一个类的属性类型是另一个类。这是最基础的关系。 💬 **比喻**:员工"属于"某个部门——Employee类中有一个Department类型的属性。 **关联关系的子类型**: | 子类型 | 说明 | 生存期 | 画法 | |--------|------|--------|------| | **普通关联** | 平等关系 | 各自独立 | 实线 | | **聚合(Aggregation)** | 整体-部分,弱关系 | 部分可独立存在 | 空心菱形 | | **组合(Composition)** | 整体-部分,强关系 | 部分随整体消亡 | 实心菱形 | 💬 **聚合 vs 组合**: - 聚合:学校由学生组成,学校解散了,**学生还在**。 - 组合:汽车由发动机组成,汽车报废了,**发动机也没意义了**。 ### 2. 依赖关系(Dependency)—— "临时使用" > **含义**:一个类的方法的参数/返回值/局部变量用了另一个类。 💬 **比喻**:你去商店买东西——你跟商店的关系只在买东西那一刻存在,买完就没关系了。 ### 3. 泛化关系(Generalization)—— "是……的一种" > **含义**:子类继承父类的属性和方法。 💬 **比喻**:狗是动物的一种——狗继承了动物的所有特征,还有自己特有的"汪汪叫"。 ### 4. 实现关系(Realization)—— "履行接口约定" > **含义**:类实现了接口中定义的所有方法。 ### 关联 vs 依赖 对比 | 维度 | 关联 | 依赖 | |------|------|------| | **强度** | 强,长期稳定 | 弱,临时短暂 | | **代码体现** | 属性类型是另一个类 | 方法参数/局部变量用了另一个类 | | **生命周期** | 对象存在就有关系 | 方法调用结束关系就结束 | | **画法** | 实线 | 虚线箭头 | --- ## ✍️ 边学边练(二) **题目**:判断以下场景属于什么关系。 1. 飞机由机翼、发动机、机身组成。(飞机-机翼) 2. 医生在医院工作。(医生-医院) 3. 学生是人。(学生-人) 4. 程序员写代码时用到开发工具。(程序员-开发工具) **答案:** 1. **组合关系**(实心菱形)—— 机翼不能脱离飞机独立存在 2. **关联关系**(普通关联)—— 医生有"所属医院"这个属性 3. **泛化关系**(继承)—— 学生是人的子类 4. **依赖关系**(虚线箭头)—— 程序员"写代码"这个方法用到了开发工具,但不是长期持有 ⚠️ **易错点**:聚合和组合都表示"整体-部分",区别在于部分能否独立存在。能独立=聚合,不能独立=组合。 --- ## 💡 三、关联关系的重要概念 ### 多重性 | 表示法 | 含义 | |--------|------| | `1` | 恰好1个 | | `0..1` | 0个或1个 | | `0..*` 或 `*` | 0个或多个 | | `1..*` | 至少1个 | | `n..m` | n到m个 | > 例:一个学生选**0..\***门课,一门课被**1..\***个学生选。 ### 关联类 > 当一个属性放在哪个类都不合适时,就用关联类。 💬 例:员工和公司之间有个"合同"——合同有"工资"属性。工资既不是员工的固有属性(换公司会变),也不是公司的固有属性。所以"合同"是一个关联类。 ### 限定关联 > 用限定符把多对多变成一对多,提高查询效率。 💬 例:一个人可以在多家银行开户(多对多)。但如果限定"在某家银行",就变成一对多了。 --- ## 💡 四、抽象类 vs 接口 | 维度 | 抽象类 | 接口 | |------|--------|------| | **属性** | 可以有 | 不能有 | | **方法实现** | 部分方法有实现 | 所有方法都没有实现 | | **关系** | 子类继承(泛化) | 类实现(实现关系) | | **多重性** | 只能继承一个 | 可以实现多个 | | **关键词** | `abstract class` | `interface` | 💬 **比喻**:抽象类像"半成品家具"(有些部分做好了,有些需要你自己完成);接口像"插座标准"(只规定了插孔形状和电压,具体怎么发电不管)。 --- ## 💡 五、版型:边界类、控制类、实体类 这是MVC模式的UML体现,期中考试经常考! | 版型 | 职责 | 常见形式 | 对应MVC | | ---------------------- | ------ | --------- | ---------- | | **边界类** `<>` | 与外界交互 | 窗口、对话框、报表 | View | | **控制类** `<>` | 协调业务逻辑 | 处理业务规则 | Controller | | **实体类** `<>` | 持久化数据 | 数据库表对应的类 | Model | 🔑 **协作关系**:边界类接收用户输入 → 控制类处理业务逻辑 → 实体类存取数据。 --- ## 📌 附录:类图常用画图符号速查 > 这一节把类图中所有的关系符号、接口、抽象类、版型、对象图等所有画图元素用字符画列出来,画类图时直接照搬即可。 ### 1. 关联关系(Association)—— 实线(可带多重性) **普通关联**(双向带多重性): ``` ┌────────┐ 1 0..* ┌────────┐ │ 老师 │ ────────────────── │ 学生 │ └────────┘ └────────┘ ``` **自关联**(一个类关联到自己): ``` ┌────────┐ │ 员工 │ │ │ │ 领导 │◀──┐ └────────┘ │ │ │ └─────┘ ``` ### 2. 聚合关系(Aggregation)—— 实线 + 空心菱形 ◇ > 部分可脱离整体独立存在。 ``` ◇ ┌────────┐ ┌────────┐ │ 班级 │ ───────────── │ 学生 │ └────────┘ └────────┘ (整体) (部分,可独立) 💬 学校没了,学生还在 —— 所以是空心菱形 ``` ### 3. 组合关系(Composition)—— 实线 + 实心菱形 ◆ > 部分不能脱离整体独立存在。 ``` ◆ ┌────────┐ ┌────────┐ │ 汽车 │ ───────────── │ 发动机 │ └────────┘ └────────┘ (整体) (部分,离不开整体) 💬 汽车报废了,发动机也没意义了 —— 所以是实心菱形 ``` ### 4. 依赖关系(Dependency)—— 虚线 + 开放箭头 ``` ┌────────┐ ┌────────┐ │ 司机 │ ─ ─ ─ ─ ─ ─ ─⇨ │ 汽车 │ └────────┘ └────────┘ (使用者) (被使用者) (虚线 + 开放箭头) ``` ### 5. 泛化关系(Generalization)—— 实线 + 空心三角 **方向**:子类 → 父类(空心三角指向父类)。 ``` ▷ ┌────────┐ ┌────────┐ │ 狗 │ ───────────── │ 动物 │ └────────┘ └────────┘ (子类) (父类) ``` ### 6. 实现关系(Realization)—— 虚线 + 空心三角 **方向**:实现类 → 接口(空心三角指向接口)。 ``` ▷ ┌────────┐ ┌──────────────┐ │ 鸟 │ ─ ─ ─ ─ ─ ─ ─ │<>│ └────────┘ │ 飞行 │ (实现类) └──────────────┘ (接口) ``` ### 7. 接口的两种画法 **普通矩形画法**(在类图中更常见): ``` ┌──────────────────┐ │ <> │ ← 关键字标识 │ 飞行 │ ← 接口名 ├──────────────────┤ │ +起飞(): void │ ← 只有声明,没有实现 │ +降落(): void │ └──────────────────┘ ``` **棒棒糖表示法**(简化版,常在组件图中使用): ``` ┌────────┐ ┌────────┐ │ 鸟 │●─ ─ ─ ─ ─ ─ ─ ─ ─ ┤ 飞行 │ (棒棒糖+连接线) └────────┘ └────────┘ (实现类) (接口) ``` ### 8. 抽象类与抽象方法 > **画法**:抽象类**类名用斜体**、抽象方法**方法名用斜体**。在字符画里用 `<>` 标识或加文字说明。 ``` ┌────────────┐ │ 动物 │ ← 实际画图时类名用斜体 ├────────────┤ │ │ ├────────────┤ │ 移动() │ ← 实际画图时方法名用斜体 │ 叫() │ └────────────┘ {abstract} ← 标注方式(实际画图用斜体) ``` ### 9. 版型(Stereotype)的画法 **边界类**: ``` ┌────────────────┐ │ <> │ ← 写在类名上方 │ 登录页面 │ ├────────────────┤ │ -用户名:String │ │ -密码:String │ ├────────────────┤ │ +提交():void │ └────────────────┘ ``` **控制类**: ``` ┌────────────────┐ │ <> │ │ 订单处理 │ ├────────────────┤ │ │ ├────────────────┤ │ +处理订单() │ │ +检查库存() │ └────────────────┘ ``` **实体类**: ``` ┌────────────────┐ │ <> │ │ 订单 │ ├────────────────┤ │ -订单号:String│ │ -金额:double │ ├────────────────┤ │ +保存() │ │ +查询() │ └────────────────┘ ``` ### 10. 对象图的画法 > 对象名格式:`对象名:类名`(对象名和类名下加**下划线**),属性有具体值。 ``` ┌─────────────────┐ │ 张三:员工 │ ← 对象名:类名,下划线 ├─────────────────┤ │ 员工号 = "E001" │ ← 属性=值 │ 姓名 = "张三" │ │ 年龄 = 28 │ └─────────────────┘ ``` **对象图与类图对比**: ``` 类图(描述规则) 对象图(描述实例) ┌──────────┐ ┌────────────────┐ │ 员工 │ │ 张三:员工 │ ├──────────┤ ├────────────────┤ │ -员工号 │ │ 员工号="E001" │ │ -姓名 │ ──> │ 姓名="张三" │ │ -年龄 │ │ 年龄=28 │ ├──────────┤ └────────────────┘ │ +查询() │ └──────────┘ ``` ### 11. 关联类的画法 > 关联类挂在关联线中间,用虚线连到关联线上。 ``` ┌────────┐ ┌────────┐ │ 员工 │ ─ ─ ─ ─ ─ ─ ─ │ 公司 │ └────────┘ │ └────────┘ │ ┌────────┐ │ 合同 │ ← 关联类(虚线连到关联线上) ├────────┤ │ -工资 │ │ -合同期│ └────────┘ ``` 🔑 **一句话记忆口诀**:实线实箭是关联,空心菱形是聚合,实心菱形是组合,虚线开放箭头是依赖;实线空三角是泛化(继承),虚线空三角是实现(接口)。 --- ## ✍️ 边学边练(三) **题目**:在线购物系统中,"用户"通过"购物页面"下单,系统"订单处理"模块检查库存后,更新"订单"数据和"库存"数据。请指出各属于哪种版型。 **答案:** - 购物页面 → **边界类**(与用户交互) - 订单处理模块 → **控制类**(协调业务逻辑) - 订单、库存 → **实体类**(持久化的数据) 完整流程:边界类("购物页面") → 控制类("订单处理") → 实体类("订单""库存") --- ## 💡 六、对象图 > **对象图 = 类图的"截图"**。类图描述通用规则,对象图描述某一时刻的具体情况。 | 类图 | 对象图 | |------|--------| | 三个格子(类名+属性+操作) | 两个格子(对象名:类名 + 属性值) | | 描述所有可能的情况 | 描述某一个时刻的快照 | | 属性定义特征(如"姓名: String") | 属性有具体值(如"姓名 = 张三") | 💬 **比喻**:类图像"菜单"(描述菜的做法),对象图像"上桌的菜"(一份具体的菜)。 --- ## 📝 章末自测 **1. 填空题** - 聚合关系中,整体不存在了,部分( ___ )存在。(能/不能) - 组合关系中,整体不存在了,部分( ___ )存在。(能/不能) - 边界类、控制类、实体类分别对应MVC中的( _____ )、( _____ )、( ___ ) **2. 判断题** - ( ) 依赖关系比关联关系更弱 - ( ) 接口可以有属性 - ( ) 抽象类可以被实例化 - ( ) 对象图是类图的实例 - ( ) 一个类只能继承一个抽象类,但可以实现多个接口 **3. 分析题** - 职工类Employee包含属性empcode、name、address、birthday。Address类包含houseNumber、streetNumber、city、zipcode。分析两个类之间的关系。 **答案:** **填空题**:能、不能、View、Controller、Model **判断题**:✅ ❌(接口无属性) ❌(抽象类不能实例化) ✅ ✅ **分析题**:**关联关系**。因为Employee类中有一个属性address,其类型是Address类。这是一个长期稳定的结构关系。多重性:Employee端1,Address端0..*(一个地址可以被多个员工使用)。 --- > 🔗 上一篇:[第3章 用例图](第03章-用例图.md) | 下一篇:[第5章 顺序图与协作图](第05章-顺序图与协作图.md)