srp要求一个类只有一个修改理由,如user类应拆分为userrepository、emailservice等;ocp要求通过抽象接口扩展功能而不修改原有代码;lsp强调子类必须完全遵守父类行为契约;isp要求接口最小化,dip要求依赖抽象而非具体实现。

因为不遵循SOLID,项目规模稍一增长,改一个功能就得通读三个模块、修五个类、测八处边界——不是代码不能跑,而是没人敢动。
SRP:一个类只该有一个__init__要关心的理由
当User类里同时出现save_to_db、send_email、validate_phone、log_activity这些方法时,它已经不是用户模型,而是一个“功能缝合怪”。每次数据库换ORM、邮件服务切API、手机号校验加正则规则,你都得打开同一个文件反复修改。
- 真正该做的:把
save_to_db交给UserRepository,send_email抽成EmailService,validate_phone放进PhoneNumberValidator - 判断依据:如果删掉其中某个方法,其余方法逻辑是否仍能独立运行?不能 → 违反SRP
- 副作用:违反SRP的类往往测试覆盖率低——你没法只测“保存”而不触发邮件发送
OCP:新增支付方式不该动OrderProcessor.process()
常见写法:if payment_type == "alipay": ... elif payment_type == "wechat": ...。一旦接入PayPal或Stripe,就得改这个函数,还可能误伤原有分支逻辑。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 正确路径:定义抽象
PaymentProcessor接口,让AlipayProcessor、WechatProcessor各自实现charge() - 关键点:
OrderProcessor只依赖PaymentProcessor协议,不关心具体是谁 - 坑:Python没有编译期接口检查,靠文档+类型注解+mypy约束;漏写
__subclasshook__或Protocol会导致子类悄悄不兼容
LSP:子类替换父类后,assert isinstance(obj, Animal)不能保你平安
比如Duck继承Bird,但重写了fly()抛出NotImplementedError——这时任何依赖Bird.fly()的代码,在传入Duck实例时就会崩。
- 本质问题:父类契约被破坏。LSP不是语法要求,是行为契约
- 自查方式:把所有父类单元测试套在子类实例上跑一遍,必须全过
- Python特例:鸭子类型让LSP更隐蔽——
list和tuple都支持[0],但append()就不是所有序列都该有
ISP + DIP:别让ReportGenerator直接import MySQLConnection
当一个报表生成器硬编码连接MySQL,它就同时耦合了业务逻辑、SQL方言、连接池配置、甚至错误重试策略。换数据库?改17个地方;加缓存层?重写整个数据获取链路。
- 拆解动作:定义
DataFetcher协议(只有fetch()),让MySQLFetcher和RedisFetcher分别实现 - 注入方式:用构造函数参数传入
DataFetcher实例,而非在类内部import或new - 容易忽略的细节:协议里别塞太多方法——
DataFetcher若定义了connect()、disconnect()、health_check(),就违背ISP;应拆成Connectable、HealthCheckable等小协议
最常被跳过的其实是LSP和ISP:前者靠测试保障,后者靠协议粒度控制,两者都不在Python语法层面强制,全靠团队对“什么算合理替换”“什么算最小接口”的共识——而这恰恰是代码腐化最快的缺口。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










