类图是三格加几条线:实测用反射直接读出类名/属性/方法,并确认父类——最常被漏掉的不是格子,是那条继承线。
8.4 说结构进类图,这一节把类图拆到可以动手画:三个格子、三种线。
一、三格:类名/属性/方法
第一格放类名,第二格属性,第三格方法,中间用横线隔开。
属性写成 名字: 类型,方法写成 名字(参数): 返回类型。
这三格不是凭记忆填的——Python 里可以直接从类上反射出来。
二、实测:反射出三格
Account 有 2 个属性(balance、pin)、3 个方法,父类是 object。
Saving 继承它,自己新增 1 个属性(rate)、1 个方法(add_interest),算上继承是 3 个属性。
注意口径:Saving 的格子里通常只写自己新增的,继承来的由那条线交代。
三、三种线:继承/关联/聚合组合
继承:实线+空心三角,箭头指向父类,读作【是一种】。
关联:实线(可带箭头),表示【有一个】,比如 Loan 关联 Book。
聚合/组合:实线+空心/实心菱形,表示【由什么组成】,组合比聚合更强(同生共死)。
画错的代价:把继承画成关联,等于说【读者有一个借阅记录】而不是【读者是一种人】——语义全反了。
四、最常被漏的是关系
新手画类图,格子填得很漂亮,线一条不画。 没有线的类图只是一张列表——它不告诉你任何结构信息。 所以先画线再填格子也行:关系理清了,格子自然就知道该写什么。
五、动手 Demo:类图表示OOP程序的结构
用 __annotations__ 数属性、用 __dict__ 数自己写的方法。
顺便把父类读出来,验证继承那条线。
import types
class Account(object):
balance: int = 0
pin: str = "0000"
def deposit(self, x): self.balance += x
def withdraw(self, x): self.balance -= x
def show(self): return self.balance
class Saving(Account):
rate: float = 0.01
def add_interest(self): self.balance += int(self.balance * self.rate)
def attrs(c):
d = {}
for k in reversed(c.__mro__):
d.update(getattr(k, "__annotations__", {}))
return d
print(len(attrs(Saving)), Saving.__mro__[1].__name__) # 3 Account
实跑输出:
--------------------------------------------------------------------
类图表示OOP程序的结构
--------------------------------------------------------------------
类图的三格(类名/属性/方法)**可以直接从代码里反射出来**。实测:
类名 属性 方法 父类
--------------------------------------
Account 2 3 object
Saving 3 1 Account
类名 Account/Saving
属性明细 balance/pin/rate
方法明细 add_interest
注 方法数只数自己写的,继承来的不算(Saving 实际可调 4 个)
关系 Saving --|> Account(继承,实测父类 = Account)
**三格里最常被漏的是【关系】**——类图画得再好,没有那条继承线就是废图。
**属性要看继承来的**:Saving 自己只声明 1 个,算上父类是 3 个。
**这就是 4.9 讲的【去除重复定义】在图上长成的样子。**
实测:Account 2 属性 3 方法、Saving 3 属性 1 方法(自己写的),父类 Account。
方法数只数自己写的,继承来的不算——Saving 实际能调 4 个方法。
关系那一行才是类图的灵魂:Saving --|> Account。
30 秒实验
- 用
Cls.__mro__打印你项目里三个类,手画它们的继承线。 - 找一个把关联画成继承的例子,说出它为什么错。
常见误区
- 以为类图只要填三个格子。没有关系线的类图等于一张列表。
- 把继承画成关联。【是一种】和【有一个】是两件事。
自测三问(点开对答案)
1. 类图三格分别是什么? —— 类名、属性、方法;属性写名字与类型,方法写名字与参数。 2. 继承和关联画法不同在哪? —— 继承是实线加空心三角(指向父类,是一种),关联是实线(有一个)。 3. 实测 Saving 有几个属性? —— 自己新增 1 个,算上继承的 2 个共 3 个;方法自己写 1 个,可调 4 个。- ☐ 8.6 使用时序图和通信图表示动作
相关笔记
- UML的使用方法之一:表示程序结构和动作 — 结构与动作的分家
- 三大要素之三:去除类的重复定义的继承 — 继承线的机制来源
- 使用类图表示根据集合论进行整理的结果 — 用类图画集合关系
- 🧩 面向对象是怎样工作的 · 索引