当前位置: 首页 > ops >正文

彻底搞懂面向对象分析(OOA)

一、先搞懂:面向对象分析到底是什么?

你不用记复杂定义 ——OOA 的核心就是 “搞清楚系统要做什么”,并把这个 “需求” 变成一个 “看得见、能沟通” 的模型

比如开发 ATM,OOA 要解决的问题是:

  • 这个系统里有哪些 “关键角色 / 东西”(比如用户、储蓄卡、银行系统)?
  • 这些角色之间会发生什么互动(比如用户插卡、银行验证密码)?
  • 系统最终要实现什么功能(比如取钱、打印凭条)?

官方点说,OOA 的三大核心工作是:

  1. 理解:吃透用户需求(比如银行说 “密码错 3 次锁卡”);
  1. 表达:把需求变成 “对象模型、动态模型、功能模型”(后文重点讲);
  1. 验证:确认模型没遗漏、没矛盾(比如 “锁卡后还能不能查余额?”)。

二、OOA 的基本过程:3 个子模型 + 5 个层次

这是 OOA 的 “骨架”,先记住一句话:先确定 “有什么”(对象模型),再看 “会发生什么”(动态模型),最后明确 “要做什么”(功能模型),5 个层次则是建模的 “步骤顺序”。

1. 3 个子模型:像剥洋葱一样理解系统

子模型

核心问题

类比(ATM 系统)

对象模型

系统里 “有什么”

桌椅、员工(对应:用户、储蓄卡、ATM 机)

动态模型

系统 “会发生什么”

顾客点餐流程(对应:插卡→输密码→取钱)

功能模型

系统 “要做什么”

厨房做菜步骤(对应:验证卡→扣余额→吐钱)

2. 5 个层次:建模的 “先后顺序”

按这个顺序做,绝对不会乱:

  1. 主题层:把系统拆成 “大模块”(比如 ATM 分 “用户交互模块”“银行通信模块”);
  1. 类与对象层:每个模块里有哪些 “关键角色”(比如 “用户交互模块” 里有 ATM 机、用户);
  1. 结构层:这些角色之间的关系(比如 “用户持有储蓄卡”“储蓄卡关联银行系统”);
  1. 属性层:每个角色的 “特征”(比如储蓄卡有 “卡号、余额、有效期”);
  1. 服务层:每个角色能 “做什么”(比如 ATM 机能 “验证密码、吐钱”)。

三、第一步:写清楚 “需求陈述”—— 别让需求变成 “罗生门”

需求是 OOA 的起点,写差了后面全错。比如银行说 “用户能取钱”,这就是典型的 “烂需求”—— 没说取多少钱、密码错了怎么办、要不要打凭条。

1. 需求陈述 3 个要点
  • 无歧义:把 “模糊词” 变 “精确描述”

坏例子:“用户能取钱”

好例子:“储蓄卡用户插入有效卡片,输入正确密码后,可提取 100~20000 元(步长 100 元)”;

  • 无遗漏:别漏 “异常场景”

比如必须写 “密码连续错误 3 次,系统锁定卡片并吐出”“余额不足时提示‘请重新输入金额’”;

  • 无矛盾:前后说法一致

不能前面写 “密码错 3 次锁卡”,后面写 “错 5 次锁卡”。

2. ATM 系统需求陈述(实战示例)

1. 用户范围:持有本行储蓄卡的个人用户;

2. 核心功能:

a. 插卡验证:系统读取卡号,向银行确认卡片是否有效(未挂失、未过期);

b. 密码验证:用户输入6位密码,银行验证正确性,错3次锁卡;

c. 取款操作:验证通过后,用户输入100~20000元(步长100),系统向银行请求扣款,扣款成功后吐钱;

d. 凭条打印:用户可选择是否打印凭条,凭条包含卡号后4位、金额、时间;

3. 异常处理:

a. 卡片无效(过期/挂失):提示“卡片无法使用”并吐卡;

b. 余额不足:提示“余额不足”并返回金额输入界面;

c. 吐钞失败:提示“交易失败”,向银行发送“撤销扣款”请求。

四、核心任务 1:建立 “对象模型”—— 确定系统里的 “人和物”

对象模型是 OOA 的基石,简单说就是 “画一张图,展示系统里的关键角色、关系和特征”。按以下 6 步来:

步骤 1:确立 “类与对象”—— 从需求里抓 “名词”
  • 方法:把需求里的 “名词 / 名词短语” 列出来,排除 “非问题域” 的词;
  • ATM 实战:

需求里的名词:用户、储蓄卡、ATM 机、银行系统、密码、金额、凭条、卡号、余额

排除非问题域:密码(是储蓄卡的属性,不是独立类)、金额(是取款事件的参数,不是类)

最终类:User(用户)、DebitCard(储蓄卡)、ATM(ATM 机)、BankSystem(银行系统)、Receipt(凭条)。

步骤 2:确立 “关联”—— 类之间的 “关系”
  • 方法:用 “动词” 描述类之间的联系,比如 “持有”“关联”“生成”;
  • ATM 实战(用 UML 类图表示,文字版如下):
    • User ←“持有”→ DebitCard(一个用户可持有多张卡,一张卡属一个用户);
    • DebitCard ←“关联”→ BankSystem(一张卡对应一个银行系统);
    • ATM ←“生成”→ Receipt(一台 ATM 可生成多个凭条);
    • ATM ←“通信”→ BankSystem(ATM 向银行发送请求)。
步骤 3:划分 “主题”—— 给类 “分组”
  • 目的:避免类太多看着乱,按 “业务模块” 分组;
  • ATM 实战:
    • 主题 1:用户交互组(User、ATM、Receipt);
    • 主题 2:银行数据组(DebitCard、BankSystem)。
步骤 4:确定 “属性”—— 类的 “特征”
  • 方法:只选 “问题域需要的特征”,排除无关的(比如储蓄卡的 “颜色” 不用管);
  • ATM 实战(代码示例:Java 类的属性定义):

// 储蓄卡类:只保留问题域需要的属性

public class DebitCard {

private String cardId; // 卡号(必需,用于识别)

private double balance; // 余额(必需,判断能否取款)

private String expiryDate;// 有效期(必需,验证卡片是否有效)

private boolean isLocked; // 是否锁定(必需,处理密码错误场景)

// 排除无关属性:cardColor(颜色)、material(材质)

}

步骤 5:识别 “继承关系”—— 减少重复代码
  • 方法:找 “同类事物的共性与个性”,比如 “用户” 里有 “储蓄卡用户”“信用卡用户”;
  • ATM 实战(代码示例:继承):

// 父类:用户(共性)

public class User {

private String name; // 姓名(所有用户都有)

private String idCard; // 身份证号(所有用户都有)

// 共性方法:登录(输入身份信息)

public boolean login(String idInfo) {

// 验证身份的通用逻辑

return true;

}

}

// 子类:储蓄卡用户(个性)

public class DebitCardUser extends User {

private List<DebitCard> debitCards; // 储蓄卡用户特有:持有多张储蓄卡

// 个性方法:绑定储蓄卡(父类没有)

public void bindCard(DebitCard card) {

this.debitCards.add(card);

}

}

步骤 6:反复修改 —— 模型不是 “一次性成品”
  • 例子:一开始漏了Receipt(凭条)类,后来看需求里有 “打印凭条”,就补充进去;
  • 原则:每次修改后,回头对照需求,确认没偏离。

五、核心任务 2:建立 “动态模型”—— 描述系统 “会发生什么”

动态模型关注 “事件和状态变化”,比如 “插卡” 这个动作会让储蓄卡从 “未插入” 变成 “已插入”。按以下 5 步来:

步骤 1:编写 “脚本”—— 模拟 “正常 / 异常场景”

脚本就是 “一步步描述用户和系统的互动”,先写正常场景,再补异常场景。

  • ATM 正常脚本(取款流程):

1. 用户(触发者)插入储蓄卡到ATM(目标)→ 参数:卡号信息;

2. ATM(触发者)向银行系统(目标)发送“验证卡片”请求→ 参数:卡号;

3. 银行系统(触发者)返回“卡片有效”→ 参数:有效信号;

4. ATM(触发者)提示用户输密码→ 参数:无;

5. 用户(触发者)输入密码→ 参数:6位密码;

6. ATM(触发者)向银行系统(目标)发送“验证密码”请求→ 参数:卡号+密码;

7. 银行系统(触发者)返回“密码正确”→ 参数:通过信号;

8. 用户(触发者)输入取款金额(比如2000)→ 参数:2000;

9. ATM(触发者)向银行系统(目标)发送“扣款请求”→ 参数:卡号+2000;

10. 银行系统(触发者)返回“扣款成功”→ 参数:成功信号+更新后余额;

11. ATM(触发者)吐钱→ 参数:2000元现金;

12. 用户(触发者)选择“打印凭条”→ 参数:打印指令;

13. ATM(触发者)生成凭条并吐出→ 参数:凭条;

14. ATM(触发者)吐卡→ 参数:储蓄卡;

15. 用户(触发者)取卡→ 流程结束。

  • ATM 异常脚本(密码错 3 次):

1. 步骤1~5同上;

2. 银行系统返回“密码错误”(第1次)→ ATM提示“密码错误,还有2次机会”;

3. 用户再输错2次→ 银行系统返回“密码错3次,锁定卡片”;

4. ATM提示“卡片已锁定,请联系银行”并吐卡;

5. 流程结束。

步骤 2:设想 “用户界面”—— 绑定 “动作和事件”

不用画复杂界面,只要明确 “用户操作” 对应 “哪个事件”:

  • ATM 界面元素:插卡口、密码键盘、金额输入键、“打印凭条” 按钮;
  • 对应关系:按 “金额输入键”→ 触发 “输入取款金额” 事件;按 “打印凭条” 按钮→ 触发 “请求打印凭条” 事件。
步骤 3:画 “事件跟踪图”—— 按 “时间轴” 展示互动

用 “时间轴 + 角色” 的方式,清晰看事件发生顺序(文字简化版):

时间轴→ 1 2 3 4 5 6

User | 插卡 | | 输密码 | 输金额 | 选打印 | 取卡

ATM | | 发验证 | 提示输密| 发扣款 | 吐钱打条| 吐卡

BankSys | | 返有效 | 返正确 | 返成功 | |

步骤 4:画 “状态图”—— 描述单个类的 “状态变化”

状态图只关注 “一个类” 的状态,比如DebitCard(储蓄卡)的状态变化:

初始状态→ 未插入 →(触发事件:插入)→ 已插入 →(触发事件:密码正确)→ 已验证

已验证 →(触发事件:输入金额并确认)→ 交易中 →(触发事件:扣款成功)→ 交易完成

交易完成 →(触发事件:吐卡)→ 已退出 → 最终状态

// 异常分支:已插入 →(触发事件:密码错3次)→ 已锁定 →(触发事件:吐卡)→ 已退出

步骤 5:审查动态模型 —— 确保 “无遗漏”
  • 检查点 1:每个脚本里的事件,是否都在状态图里有对应?

比如 “密码错 3 次” 事件,在DebitCard的状态图里有 “已插入→已锁定” 的转换;

  • 检查点 2:是否覆盖所有异常场景?

比如 “吐钞失败” 事件,是否在ATM的状态图里有 “交易中→交易失败→吐卡” 的处理。

六、核心任务 3:建立 “功能模型”—— 描述系统 “要做什么”

功能模型用 “数据流图(DFD)” 表示,关注 “数据怎么流动、怎么处理”,比如 “卡号” 从用户到 ATM,再到银行,最后返回 “有效 / 无效” 信号。

步骤 1:画 “基本系统模型图”—— 确定 “系统边界”

先明确 “哪些是系统内的,哪些是外部的”:

  • 外部实体:User(用户)、BankSystem(银行系统);
  • 系统边界:ATM 系统(我们要开发的部分);
  • 处理框:ATM 核心处理(最顶层的功能);
  • 数据流:

外部→系统:用户操作指令(插卡、输密码、输金额)、银行响应(有效 / 无效、成功 / 失败);

系统→外部:ATM 提示(输密码、余额不足)、吐钱、吐卡、凭条。

步骤 2:画 “功能级数据流图”—— 拆分 “顶层功能”

把 “ATM 核心处理” 拆成具体的小功能,比如:

1. 卡验证处理:

输入:卡号(来自插卡);

输出:卡状态(有效/无效,到提示模块)、有效卡号(到密码验证处理);

2. 密码验证处理:

输入:有效卡号(来自卡验证)、用户输入的密码(来自用户);

输出:密码状态(正确/错误,到提示模块)、验证通过信号(到取款处理);

3. 取款处理:

输入:验证通过信号(来自密码验证)、取款金额(来自用户);

输出:扣款请求(到银行系统)、扣款结果(到吐钱模块);

4. 凭条打印处理:

输入:交易信息(卡号后4位、金额、时间,来自取款处理)、打印指令(来自用户);

输出:凭条(到用户)。

步骤 3:描述 “处理框功能”—— 只说 “做什么”,不说 “怎么做”
  • 坏例子(写了算法):“取款处理:计算吐钞的 100 元张数(金额 / 100),控制电机转动吐钞”;
  • 好例子(只说功能):“取款处理:接收用户输入的取款金额,向银行系统发送扣款请求,接收扣款结果后,触发吐钞模块执行吐钞操作”。

七、最后一步:定义 “服务”—— 给类加 “能做的事”

服务就是类的 “方法”,比如ATM类的verifyPassword()(验证密码)方法。按以下 4 个来源找服务:

1. 常规行为:类 “天生该有的能力”
  • 比如DebitCard的getBalance()(获取余额)、isValid()(判断是否有效);
  • 代码示例:

public class DebitCard {

// 常规服务:获取余额

public double getBalance() {

return this.balance;

}

// 常规服务:判断卡片是否有效(未过期、未锁定)

public boolean isValid() {

return !this.isLocked && LocalDate.now().isBefore(LocalDate.parse(this.expiryDate));

}

}

2. 从事件导出:动态模型里的 “事件” 对应服务
  • 比如 “插卡事件”→ ATM的handleCardInsert()(处理插卡)服务;
  • “密码验证事件”→ ATM的verifyPassword()(验证密码)服务;
  • 代码示例:

public class ATM {

private BankSystem bankSystem; // 依赖银行系统

// 从“密码验证事件”导出的服务

public boolean verifyPassword(DebitCard card, String password) {

// 调用银行系统的验证接口

return bankSystem.checkPassword(card.getCardId(), password);

}

}

3. 与数据流图对应:处理框对应服务
  • 比如数据流图里的 “取款处理”→ ATM的executeWithdrawal()(执行取款)服务;
  • 代码示例:

public class ATM {

// 与“取款处理”框对应的服务

public boolean executeWithdrawal(DebitCard card, double amount) {

// 1. 向银行发送扣款请求

boolean deductSuccess = bankSystem.deductBalance(card.getCardId(), amount);

// 2. 扣款成功则吐钱

if (deductSuccess) {

this.dispenseCash(amount); // 调用吐钱服务

return true;

}

return false;

}

}

4. 利用继承减少冗余:子类复用父类服务
  • 比如User类的login()(登录)服务,DebitCardUser子类直接继承,不用重写;
  • 若子类有特殊需求,再重写(比如CreditCardUser的登录需要额外验证信用卡有效期)。

八、小结:小白学好 OOA 的 3 个关键

  1. 别被术语吓住:OOA 不是 “玄学”,核心就是 “理解需求→建 3 个模型”,全程用 ATM 这样的生活案例对照;
  1. 按步骤来:需求→对象模型→动态模型→功能模型→服务,一步错了回头改,别跳步;
  1. 多练手:看完这篇,试着用 “网购系统”(用户、商品、订单、支付系统)练一遍,马上就熟了。

记住:好的分析模型,是用户、开发、产品都能看懂的 “沟通工具”,不是只有程序员才懂的 “天书”。只要你能把 “系统要做什么” 说清楚、画明白,就是合格的 OOA!

还想看更多干货,关注同名公众昊“奈奈聊成长”!!!

http://www.xdnf.cn/news/19905.html

相关文章:

  • Linux内存管理章节一:深入浅出Linux内存管理:从物理内存到ARM32的用户与内核空间
  • 逻辑回归基础
  • .NET GcPDF V8.2 新版本:人工智能 PDF 处理
  • Spring Boot 根据配置优雅的决定实现类
  • Meshroom 2025.1.0安装及使用参数模板介绍:二维图片转三维重建
  • 因为对象装箱拆箱导致的空指针异常
  • C#强制类型转换(显示转换)和安全类型转换
  • 野火STM32Modbus主机读取寄存器/线圈失败(三)-尝试将存贮事件的地方改成数组(非必要解决方案)(附源码)
  • VBA中类的解读及应用第二十七讲:利用类完成查找的方案-5
  • SVT-AV1 svt_aom_motion_estimation_kernel 函数分析
  • 详细学习计划
  • 百度前端社招面经
  • 云手机运行是否消耗自身流量?
  • Docker(④Shell脚本)
  • 【RNN-LSTM-GRU】第五篇 序列模型实战指南:从选型到优化与前沿探索
  • 应对反爬:使用Selenium模拟浏览器抓取12306动态旅游产品
  • 40,.Ansible角色(roles)
  • 具身智能多模态感知与场景理解:视觉探索
  • 如何本地编译servicecomb-java-chassis
  • Focal Loss
  • Elasticsearch 8 中 Nested 数据类型的使用方法
  • 【文献解读】ceRNA机制研究经典思路
  • Spring Boot项目中MySQL索引失效的常见场景与解决方案
  • 从群体偏好到解构对齐:大模型强化学习从GRPO到DAPO的“认知”进化
  • 【高并发内存池】四、中心缓存的设计
  • 疯狂星期四文案网第60天运营日记
  • GEO排名优化效益分析:为何AI搜索优化服务是当下性价比最高的流量投资?
  • 学习资料1(粗略版)
  • Web详解
  • WebSocket简述与网络知识回顾