Files
obsidian/软件需求分析/各章笔记/第08章-包图.md

12 KiB
Raw Permalink Blame History

第8章 包图

考试重要度:★★
核心内容:包的概念与可见性、包之间的依赖与泛化关系、四大设计原则


📢 从文件夹理解包图

💬 你电脑上肯定有文件夹(目录),用来把相关文件放在一起。

在UML中就是"文件夹"——把关系密切的类、接口、组件等放在一起。

┌─────────────────┐
│  包名           │
│  ┌───────────┐  │
│  │ + 公开类  │  │  ← 被import后外部可用
│  │ # 受保护  │  │  ← 只有子包可用
│  │ - 私有类  │  │  ← 只有包内部可用
│  └───────────┘  │
└─────────────────┘

💡 一、包的可见性

跟类的可见性一样,包中的元素也有三种可见性:

可见性 符号 含义
公有 + 任何导入此包的包都可以用
受保护 # 只有子包可以用
私有 - 只有包内部可以用

💡 二、包之间的关系

1. 依赖关系

包A中的某个类依赖于包B中的某个类 → 包A依赖于包B。

⚠️ 注意:包之间的依赖关系没有传递性A依赖BB依赖C不等于A依赖C。

2. 泛化关系

子包继承父包中可见性为public和protected的元素。

📌 包图各元素的画法速查

这一节把包图里所有的画图元素(包本身、依赖、泛化)用字符画列出来。

① 包的两种画法

标准文件夹画法(最常用):

  ┌──────────────┐
  │   UI层       │   ← 上方有"小标签"(像文件夹的舌头)
  └──────────────┘

字符画表示(小标签在左上角):

  ┌────────────┐
  │┌─┐         │
  ││ │         │
  │└─┘─────────┤
  │   UI层      │
  │             │
  │ ┌─────────┐ │
  │ │  登录页  │ │   ← 包内可以嵌套子包或类
  │ └─────────┘ │
  └─────────────┘

简化画法(只用矩形):

  ┌──────────────┐
  │    UI层      │
  │  ┌────────┐  │
  │  │ 登录页  │  │
  │  └────────┘  │
  │  ┌────────┐  │
  │  │ 主页面  │  │
  │  └────────┘  │
  └──────────────┘

② 包的嵌套

  ┌──────────────────────┐
  │      电子商务系统      │
  │  ┌──────────┐        │
  │  │  用户模块  │        │
  │  │ ┌──────┐ │        │
  │  │ │登录类│ │        │
  │  │ └──────┘ │        │
  │  │ ┌──────┐ │        │
  │  │ │注册类│ │        │
  │  │ └──────┘ │        │
  │  └──────────┘        │
  │  ┌──────────┐        │
  │  │  订单模块  │        │
  │  └──────────┘        │
  └──────────────────────┘

③ 包的可见性符号

  ┌────────────────┐
  │ ┌─┐           │
  │ │+│ 公开类     │   ← + 公有:任何外部包都可用
  │ └─┘───────────┤
  │ ┌─┐           │
  │ │#│ 受保护类   │   ← # 受保护:只有子包可用
  │ └─┘───────────┤
  │ ┌─┐           │
  │ │-│ 私有类     │   ← - 私有:只有包内部可用
  │ └─┘───────────┤
  │                │
  └────────────────┘

④ 包之间的依赖关系 —— 虚线 + 开放箭头

一个包中的类引用另一个包中的类 → 包之间形成依赖。

  ┌──────────────┐                ┌──────────────┐
  │   UI层       │                │  业务层       │
  │              │                │              │
  │ ┌────────┐  │                │ ┌────────┐  │
  │ │登录窗口 │  │                │ │登录服务 │  │
  │ └────────┘  │                │ └────────┘  │
  │              │                │              │
  └──────────────┘                └──────────────┘
            │                              ▲
            └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘
                  虚线 + 开放箭头
              依赖方向UI层 依赖 业务层)

⚠️ 依赖方向:箭头从"使用者"指向"被使用者"(类似类图里的依赖)。

⑤ 包之间的泛化关系 —— 实线 + 空心三角

子包继承父包的内容。子包继承父包中public 和 protected 的元素。

  ┌──────────────┐                    ┌──────────────┐
  │   业务层      │                    │   通用层      │
  │   (子包)     │ ─ ─ ─ ─ ─ ─ ─ ▷  │   (父包)     │
  │              │   空心三角          │              │
  │ ┌────────┐  │                    │ ┌────────┐  │
  │ │订单处理 │  │                    │ │日志工具 │  │
  │ └────────┘  │                    │ └────────┘  │
  │ ┌────────┐  │                    │ ┌────────┐  │
  │ │支付处理 │  │                    │ │通用工具 │  │
  │ └────────┘  │                    │ └────────┘  │
  └──────────────┘                    └──────────────┘

⚠️ 泛化方向:空心三角指向父包(与类图泛化一致)。

⑥ 完整包图示例

  ┌────────────────┐
  │   表现层       │
  │  ┌────────┐   │
  │  │登录页  │   │
  │  └────────┘   │
  │  ┌────────┐   │
  │  │主窗体  │   │
  │  └────────┘   │
  └───────┬────────┘
          │  依赖
          ╌ ╌ ╌ ╌ ╌ ╌ ╌
          ▼
  ┌────────────────┐         ▷         ┌────────────────┐
  │   业务层       │ ─ ─ ─ ─ ─ ─ ─ ─ ─│   通用层        │
  │                │   泛化             │                │
  │  ┌────────┐   │                    │  ┌────────┐   │
  │  │登录管理 │   │                    │  │日志工具 │   │
  │  └────────┘   │                    │  └────────┘   │
  │  ┌────────┐   │                    │  ┌────────┐   │
  │  │订单管理 │   │                    │  │数据校验 │   │
  │  └────────┘   │                    │  └────────┘   │
  └───────┬────────┘                    └────────────────┘
          │ 依赖
          ╌ ╌ ╌ ╌ ╌ ╌ ╌
          ▼
  ┌────────────────┐
  │   数据层       │
  │  ┌────────┐   │
  │  │用户DAO │   │
  │  └────────┘   │
  │  ┌────────┐   │
  │  │订单DAO │   │
  │  └────────┘   │
  └────────────────┘

🔑 一句话记忆口诀:包用文件夹画,标签是包名;包间依赖是虚线开放箭头(指向被依赖),包间泛化是实线空心三角(指向父包);包可以嵌套,元素分+/-可见性。


💡 三、包的四大设计原则

这些原则告诉你怎么把类分到不同的包里

1. 重用等价原则REP

把可以一起复用的类放在一个包中。包 = 可重用的单元。

💬 就像一个工具包——扳手和螺丝刀放在一起,因为它们总是一起用。

2. 共同闭包原则CCP

把需要同时修改的类放在一个包中。

💬 修改了类A就必须修改类B那它们应该在一个包里——改一个包就够了。

3. 共同重用原则CRP

不会一起用的类不要放在同一个包里。

💬 别把厨房用品和修车工具放一起——要用厨房用品的人不需要修车工具。

4. 非循环依赖原则ADP

包之间的依赖关系不能形成环

💬 A→B→C→A 这样的循环依赖会严重妨碍复用。破解方法:提取共同接口或拆分包。

🔑 核心目标:高内聚、低耦合

原则 作用
高内聚 包内的类关系紧密REP + CCP
低耦合 包之间的依赖尽量少CRP + ADP

✍️ 边学边练

题目:判断以下做法是否合理。

  1. 把订单处理类和用户登录类放在同一个包
  2. A包依赖B包B包依赖C包C包依赖A包
  3. 把所有工具类放在一个util包中让其他包依赖它
  4. 把用户界面类、数据库访问类、业务逻辑类放在同一个包

答案:

  1. 不合理 — 违反CRP不会一起使用的类不要放一起。订单处理的人不需要登录功能。
  2. 不合理 — 违反ADP循环依赖
  3. 合理 — 符合REP工具类作为可重用单元
  4. 不合理 — 违反CCP和CRP。不同层次的类界面/数据/逻辑)修改原因不同,应该分开。

⚠️ 实用建议通常按层次分包UI层、业务层、数据层而不是按功能分包。


📝 章末自测

1. 填空题

  • 包的四大设计原则缩写是:( ___ ___ )、( ___ ___ )、( ___ ___ )、( ___ ___
  • ADP原则要求包之间的依赖不能形成 ___ ___
  • 包中元素的三种可见性是:公有( ___ ___ )、受保护( ___ ___ )、私有( ___ ___ )

2. 简答题

  • 简述REP和CRP之间的矛盾是什么
  • 包图和组件图的关系是什么?

答案: 填空题REP、CCP、CRP、ADP循环+、#、-

简答题

  • REP说要把可一起复用的类放在一个包这可能导致一个包很大包含所有可能用到的类CRP说不会一起用的类要分开这可能导致很多小包。两者需要权衡。
  • 包存放组件,组件包含类。包相当于文件夹,组件相当于文件。部署时:类→组件→包→结点。

🔗 上一篇:第7章 组件图与部署图 | 下一篇:第9章 数据建模