一、UML 构造块:UML 的“基础积木零件”🧩
UML 的构造块就像搭乐高的 基础零件包——要拼出复杂的软件模型,得先搞懂“有哪些核心零件(事物)”“零件怎么正确拼接(关系)”“拼好后怎么展示成果(图)”,三者缺一不可~
课本明确说构造块包括“事物、关系、图”三部分,咱们用“搭城堡”来类比更直观:
- 📦 事物 = 乐高积木块(比如“城墙块”“城门块”“小人块”,是构成模型的核心元素);
- 🔗 关系 = 积木的拼接方式(比如“凸点插凹孔”“上下叠放”“左右拼接”,规定元素间的关联规则);
- 🖼️ 图 = 拼好的城堡成品(把“零件 + 拼接方式”组合起来,直观展示模型的整体或局部效果)。
二、事物:UML 里的“积木块类型”📦
“事物”是 UML 里的 核心元素实体,就像乐高有“基础方块、动效块、收纳盒、贴纸”等不同功能的零件,事物也分 4 大类,每类都有明确的“职责”:
1. 结构事物:静态的“实体积木”(软件里的“看得见、摸得着”的部分)
结构事物是软件的 静态骨架,相当于城堡的“城墙、城门、塔楼”——不随时间变化,是核心基础。常见的有:
- 类(class):最常用的结构事物!像“乐高小人模板”——定义了“有什么属性(比如小人的身高、性别、衣服颜色)”“能做什么动作(比如走路、说话、拿东西)”。UML 里用“矩形”表示,直接对应代码里的类结构👇(初学者友好版):
// UML“类”对应的 Java 代码示例(Python、C# 结构类似)public class User { // 类名 = 模板名称
// 属性 = 小人的特征
private String name; // 姓名
private int age; // 年龄
private String phone; // 手机号
// 方法 = 小人的动作
public void login() { // 登录动作
System.out.println(name + "登录成功!");
}
public void order() { // 下单动作
System.out.println(name + "发起了订单~");
}
}
💡 实践应用:做电商 APP 时,“用户”“商品”“订单”都是“类”——先画 UML 类图定好属性和方法,再写代码,不会漏逻辑!
- 接口(interface):像“乐高小人的‘可动关节标准’”——只规定“能做什么动作(比如‘能飞’‘能发光’)”,但不规定“怎么实现这个动作”。对应代码里的接口,类只要“实现”接口,就必须写具体逻辑:
// UML“接口”对应的 Java 代码
public interface IFlyable { // 接口名(通常加 I 开头区分)void fly(); // 只定义方法名称和参数,不写实现逻辑}
// 类实现接口(必须兑现接口的“承诺”)public class Bird implements IFlyable {
@Override
public void fly() {
// 具体实现“飞”的逻辑
System.out.println("小鸟扇动翅膀,飞向天空~");
}
}
public class Plane implements IFlyable {
@Override
public void fly() {
// 不同类的实现逻辑不一样
System.out.println("飞机启动引擎,平稳起飞~");
}
}
💡 初学者理解:接口是“统一标准”——比如“飞”的标准,小鸟和飞机都能实现,但实现方式不同,UML 里用“圆圈 + 实线”表示接口和类的关系。
除此之外,结构事物还有 协作(collaboration)(多个类一起完成某个功能,比如“下单协作”= 用户 + 订单 + 支付类)、用例(use case)(用户的操作场景,比如“登录用例”“下单用例”)、组件(component)(封装好的模块,比如“支付组件”“登录组件”)等。
2. 行为事物:动态的“动作积木”(软件里的“过程和变化”)
行为事物是软件的 动态行为,相当于城堡里“小人走路、城门开关、灯光闪烁”——随时间变化,描述“发生了什么”。常见的有:
- 交互(interaction):比如“用户点击下单按钮 → 系统生成订单 → 发送支付通知”的完整过程,UML 里用“带箭头的消息”表示谁给谁发指令,后续会学“时序图”专门画这个;
- 状态机(state machine):比如“订单从‘待支付’→‘已支付’→‘已发货’→‘已签收’”的状态变化,像“乐高小人从‘站着’→‘坐着’→‘躺着’的切换规则”,用“状态图”展示。
3. 分组事物:装积木的“收纳盒”(组织元素,方便管理)
分组事物最常用的是 包(package)——像把“城门相关积木”放进一个盒子,“塔楼相关积木”放进另一个盒子,避免零件混乱。对应软件里的“模块”,比如电商 APP 里的“用户模块”“商品模块”“订单模块”,每个模块用一个包管理,UML 里用“带标签的文件夹”表示。
💡 实践价值:大项目里有上百个类,用包分组后,画图、看代码都能快速定位——比如找“支付相关”的类,直接打开“支付包”就行,不用在所有类里翻!
4. 注释事物:积木上的“便签”(添加说明,避免误解)
注释事物就是 备注说明,像在乐高积木上贴便签写“这个块是城门顶部”,UML 里用“带虚线的文本框”表示。比如在“订单类”旁边加注释:“此类存储订单核心信息,不包含支付细节(支付细节在 Payment 类)”,队友看模型时能快速理解设计意图。
⚠️ 注意:注释只加“必要说明”,别写废话——比如“这是一个类”这种没必要的注释,反而增加冗余!
三、关系:积木的“拼接方式”🔗
关系是“事物之间的连接规则”,就像乐高积木的“凸点插凹孔”“上下叠放”“左右拼接”——没有关系,零散的积木拼不成城堡,UML 里有 4 种核心关系,覆盖 90% 的应用场景:
1. 关联:长期稳定的“绑定关系”(像“小人和他的背包”)
关联是 最常用的关系,表示两个事物“长期共存、相互关联”,比如“用户”和“订单”(一个用户可以有多个订单,一个订单属于一个用户)、“学生”和“班级”(一个班级有多个学生)。
UML 里用“实线”表示关联,还能在实线上标“数量”(比如“1 个用户对应 0..* 个订单”,0..* 表示 0 到多个)。
2. 依赖:临时的“借用关系”(像“小人临时借用工具铲”)
依赖是 短期、临时的关系——一个事物需要“借用”另一个事物的功能,用完就断联,比如“订单”生成时需要“支付工具类”的“计算金额”功能,但订单生成后,就不用依赖支付工具类了。
UML 里用“带箭头的虚线”表示(箭头指向被依赖的事物),对应代码里的“局部变量”或“方法参数”:
// 依赖关系的代码示例
public class Order {
// 订单生成时,依赖 PaymentTool 的计算功能
public void createOrder(PaymentTool tool, double price) {double finalPrice = tool.calculate(price); // 借用 PaymentTool 的 calculate 方法
System.out.println("订单金额:" + finalPrice);
}
}
// 被依赖的类
public class PaymentTool {public double calculate(double price) {return price * 0.9; // 假设打 9 折}
}
💡 初学者区分:关联是“长期持有”(比如用户有订单),依赖是“临时借用”(比如订单临时用支付工具),别搞混啦!
3. 泛化:“继承关系”(像“乐高‘警察小人’是‘小人模板’的特殊版本”)
泛化就是“子类继承父类”——子类拥有父类的所有属性和方法,还能加自己的特殊属性 / 方法。比如“学生”“老师”都是“用户”的子类,它们都有“姓名、年龄”(父类属性),但“学生”有“学号”,“老师”有“工号”(子类特殊属性)。
UML 里用“带空心三角的实线”表示(三角指向父类),对应代码里的“extends”关键字:
// 泛化关系的代码示例
public class User { // 父类(基类)private String name;
private int age;
public void login() {System.out.println(name + "登录成功");
}
}
// 子类继承父类
public class Student extends User {
private String studentId; // 子类特殊属性:学号
// 子类可以重写父类方法,也能加新方法
public void study() {System.out.println(name + "正在学习~");
}
}
public class Teacher extends User {
private String teacherId; // 子类特殊属性:工号
public void teach() {System.out.println(name + "正在讲课~");
}
}
🤖 复杂场景应用:比如“支付方式”父类,子类有“微信支付”“支付宝支付”“银行卡支付”——父类定义“支付”方法,子类各自实现具体逻辑,后续加“银联支付”,只需要加个子类,不用改父类代码,符合“开闭原则”!
4. 实现:接口和类的“绑定关系”(像“小人按‘可动标准’做动作”)
实现是“接口和类的约定关系”——类承诺“实现接口的所有方法”,比如“IFlyable 接口”定义了“fly()”方法,“Bird 类”“Plane 类”实现这个接口,就必须写“fly()”的具体逻辑。
UML 里用“带空心三角的虚线”表示(三角指向接口),对应代码里的“implements”关键字(前面接口部分已举例)。
四、图:拼好的“积木成品”🖼️
“图”是 事物 + 关系的组合展示——就像把积木按“拼接方式”拼好的城堡成品,能直观呈现模型的“静态结构”或“动态行为”,UML 的图分两大类,覆盖软件开发全流程:
1. 结构图:展示“静态骨架”(像城堡的“建筑蓝图”)
结构图聚焦“事物的组成和关系”,不关心“变化”,常见的有:
- 类图(最常用!展示类、属性、方法和关系);
- 对象图(类图的“实例化版本”,比如“用户张三”“订单 20240520”的具体关联);
- 组件图(展示软件的“模块拆分”,比如“登录组件”“支付组件”的依赖关系);
- 部署图(展示软件“部署到硬件”的情况,比如“APP 部署在手机”“后台服务部署在服务器”)。
💡 实践场景:需求分析完成后,先画“类图”定核心实体,再画“组件图”拆模块,开发前大家对“做什么、怎么拆”达成共识,避免后期返工!
2. 行为图:展示“动态流程”(像城堡的“活动动画”)
行为图聚焦“事物的动作和变化”,描述“发生了什么、怎么发生的”,常见的有:
- 用例图(展示“用户能做什么”,比如“用户登录”“下单”“退款”);
- 时序图(展示“对象之间的交互顺序”,比如“用户点击下单→系统调用订单类→调用支付类→返回结果”);
- 状态图(展示“对象的状态变化”,比如订单的状态流转);
- 活动图(展示“一个流程的步骤”,比如“用户退款流程”:申请退款→审核→退款成功)。
3. UML 1.4 vs UML 2:“乐高新旧版本”的区别
UML 也在不断升级,就像乐高从旧版到新版,增加了更实用的功能:
- UML 1.4:早期版本,图的种类较少,比如“交互图”只分“顺序图”和“协作图”;
- UML 2:目前主流版本,新增了“通信图”“定时图”等,还优化了“活动图”“状态图”的表达能力——比如支持“子图嵌套”(把复杂流程拆成小图),能展示更复杂的业务场景。
🤖 初学者建议:直接学 UML 2!现在主流的建模工具(比如 StarUML、DrawIO)都默认支持 UML 2,不用纠结旧版本,学最新的更实用~