🧩 第八章 UML:查看无形软件的工具
📄 一句话概括

类图是三格加几条线:实测用反射直接读出类名/属性/方法,并确认父类——最常被漏掉的不是格子,是那条继承线。

📝 本节和前面几节的关系

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 秒实验

  1. 用 Cls.__mro__ 打印你项目里三个类,手画它们的继承线。
  2. 找一个把关联画成继承的例子,说出它为什么错。

常见误区

  1. 以为类图只要填三个格子。没有关系线的类图等于一张列表。
  2. 把继承画成关联。【是一种】和【有一个】是两件事。
自测三问(点开对答案) 1. 类图三格分别是什么? —— 类名、属性、方法;属性写名字与类型,方法写名字与参数。 2. 继承和关联画法不同在哪? —— 继承是实线加空心三角(指向父类,是一种),关联是实线(有一个)。 3. 实测 Saving 有几个属性? —— 自己新增 1 个,算上继承的 2 个共 3 个;方法自己写 1 个,可调 4 个。

相关笔记