两套面向对象的【标准语言】:UML 用一组标准图把设计画出来(类图最常用);设计模式把前辈踩坑后总结的方案起好名字(GoF 23 种分三类)。模式是名字化的经验——说【这里用单例】一个词顶十分钟解释。
一、UML:面向对象的通用画法
UML(统一建模语言)是一组标准图形记号,常用几张:
| 图 | 画什么 |
|---|---|
| 类图 | 类的属性方法+类间关系(本章 5-21 全是它的词汇) |
| 时序图 | 对象间消息往来的时间顺序 |
| 用例图 | 系统功能与使用者 |
| 状态图 | 一个对象的状态流转 |
类图读法三分钟入门:矩形=类(三格:名字/字段/方法);箭头样式区分关系——空心三角=继承(泛化)、空心菱形=聚合、实心菱形=组合、普通箭头=依赖。UML 2.x 时代 ideas:图不用全会画,类图+时序图覆盖日常八成场景。
二、设计模式:有名字的套路
设计模式=反复出现的设计问题的成熟解法。1994 年 GoF(Gang of Four 四人帮)的《设计模式》总结 23 种,分三类:
- 创建型(怎么造对象):单例(全局唯一)、工厂(把 new 收拢到一处)、建造者、原型;
- 结构型(怎么拼装类):适配器(旧接口套新壳)、装饰器(动态加功能)、外观、代理、组合、桥接、享元;
- 行为型(怎么协作):观察者(一对多通知)、策略(算法可替换)、迭代器(4-9 已学)、命令、状态、模板方法等。
模式的正确用法:先有问题,再找模式——拿着模式找问题是反面教材(过度设计:三层包装只为调一个函数)。
三、模式与多态的关系
几乎全部行为型模式的地基都是 5-19 的多态+接口:策略模式=把算法族做成可替换的接口实现;观察者=订阅者都实现同一个 update 接口。学模式前先把多态吃透,模式只是多态在具体场景的固定打法。
四、动手 Demo:单例与策略各来一发
# 模式一:单例(全局唯一)——用模块级实现最 Pythonic
class Config:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
a, b = Config(), Config()
print("单例:", a is b)
# 模式二:策略(算法可替换)——排序键即策略
def by_price(item):
return item["price"]
def by_sales(item):
return -item["sales"] # 负号 = 降序
items = [
{"name": "键盘", "price": 300, "sales": 50},
{"name": "鼠标", "price": 100, "sales": 200},
{"name": "显示器", "price": 900, "sales": 30},
]
print("按价格:", [x["name"] for x in sorted(items, key=by_price)])
print("按销量:", [x["name"] for x in sorted(items, key=by_sales)])
沙箱实跑输出:
单例: True
按价格: ['鼠标', '键盘', '显示器']
按销量: ['鼠标', '键盘', '显示器']
看到什么算成功:两次 Config() 拿到同一个对象(True);两种策略排序各自正确。
读结果:__new__ 拦截实例化保证全局唯一——配置、连接池、日志器常用单例(但教材提醒:全局状态是测试的敌人,能不用就不用)。策略 Demo 里 Python 的 key= 函数就是活生生的策略模式——把【怎么排】从【排这个动作】里拆出来随时替换,与 5-19 的鸭子类型一脉相承。
五、30 秒实验
给 Config 加 def __init__(self): self.value = 42,再 print 两实例的 value——发现每次 init 都重跑(值覆盖但对象同一个)。单例的正确 Python 写法其实是模块级变量——语言给了更简单的路,模式别硬套。
六、常见误区
| 误区 | 真相 |
|---|---|
| 23 个模式都要背 | 记住名字和用途即可;动手时查——用着用着自然熟 |
| 用了模式=代码高级 | 为用而用是过度设计;模式解决重复出现的问题 |
| UML 图越全越好 | 类图+时序图覆盖八成日常;其余按需取用 |
自测三问(点击展开)
1. **GoF 模式分哪三类?** 答:创建型(怎么造)、结构型(怎么拼)、行为型(怎么协作)。 2. **类图里空心三角和实心菱形各表什么?** 答:空心三角=继承(泛化);实心菱形=组合(整体掌控部分的生命周期)。 3. **单例适合什么场景?风险是什么?** 答:全局唯一资源(配置、连接池);风险=全局状态难测试,Python 常用模块级变量替代。- ☐ 5-20 学习完成
相关笔记
- 迭代器 —— 迭代器模式本身(行为型之一)
- 多态与接口 —— 模式的地基
- ⌨️ 编程原理 · 索引 —— 全课路线图