上帝类从__init__初始化多个职责对象起就已形成;识别信号包括:多依赖初始化、方法名混用动词前缀、单元测试需mock多个外部依赖;拆分应遵循grasp信息专家原则,按数据归属分配职责,并通过依赖注入解耦。

直接说结论:上帝类不是写多了才出现的,而是从第一行 __init__ 开始就埋了雷——只要一个类同时承担“存数据、做计算、发通知、写日志、校验权限”,它就已经是上帝类了。
识别上帝类的三个信号
不用等代码长到1000行,这几个现象一出现,基本就能判定:
-
self.users、self.email_service、self.logger、self.validator全在一个__init__里初始化 - 方法名混着用动词前缀:
send_email、validate_user、log_action、export_csv - 单元测试必须 mock 至少4个外部依赖才能跑通一个方法
拆分时优先按“信息专家”原则分配职责
GRASP 的 信息专家 原则比“高内聚低耦合”更具体:谁持有数据,谁就该处理跟那数据最直接相关的逻辑。别凭感觉分,看字段归属。
- 如果类里有
self.balance和self.currency,那calculate_interest就该归它;但send_sms_alert不该——短信服务不持有余额信息 - 如果
User类里存了self.role,权限检查逻辑可以留;但generate_monthly_report不该——报表需要聚合N个用户,不是单个用户的“信息” - 遇到“这个功能该放哪儿”,先问:当前类有没有这个操作所需的全部数据?没有,就往外推,推给能拿到那些数据的协作方
用依赖注入代替内部创建,切断隐式耦合
上帝类常偷偷 new 出其他对象,比如在 process_order 里直接调用 EmailService() 或 DBConnection()。这会让测试和替换实现变得极难。
- 把外部依赖作为参数传进
__init__或方法,而不是在内部用import+()创建 - 接口要窄:不要传整个
Database实例,只传需要的save_user函数或 Repository 接口 - 避免
if config.mode == 'prod': use_real_email() else: use_stub()这种分支——那是配置逻辑,不该污染业务类
警惕“组合”变成新上帝类的温床
有人把上帝类拆成 UserManager + EmailSender + Logger,然后让 UserManager 持有后两者实例——这没解决问题,只是把上帝类换了个名字。关键不在拆,而在“谁控制谁”。
真正解耦的标志是:User 类完全不知道 EmailSender 的存在;EmailSender 只接受原始数据(如 user.email、template_name),不碰 User 对象本身。中间那层协调逻辑,应该放在用例层(比如 RegisterUserUseCase),而不是塞进某个实体类里。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











