六大设计原则是日常编码的思考习惯而非检查清单:单一职责强调按变更原因拆分类,开闭原则主张用接口封装已知变化点,里氏替换与依赖倒置协同保障子类可安全替换父类,接口隔离和迪米特法则分别聚焦调用方视角的接口精简与调用链路的松耦合。

六大设计原则不是检查清单,而是日常写类时的思考习惯。关键不在于“有没有用上全部”,而在于每次加一个方法、拆一个类、定义一个接口时,是否自然地回应了某个原则背后的实际问题。
单一职责:从“谁该改这个类”倒推职责边界
判断一个类是否职责单一,就问:如果支付逻辑要换渠道,库存策略要调阈值,短信模板要更新——这三件事哪件变了,会逼你打开这个类去改?只要答案超过一个,就该拆。
- 把“订单创建”和“订单通知”分开:前者管数据校验与持久化,后者只管调用短信/邮件服务
- 避免在 Service 类里直接 new Logger 或拼 SQL 字符串;日志交给 LogService,SQL 交给 Mapper 或 Repository
- Android 开发中,Activity 不该同时持有网络请求、数据解析、UI 刷新逻辑;每块抽成独立类或用 ViewModel + UseCase 分层
开闭原则:用接口兜住变化点,而不是等需求来了再改
不是所有地方都要提前抽象,而是盯住那些已知会变、且变法明确的地方。比如支付方式、导出格式、审批流程节点。
- 定义 PaymentStrategy 接口,支付宝、微信、银行卡各写一个实现类;新增 Apple Pay 只需加新类,不碰调度器
- 报表导出不写死为 ExcelExport,而是声明 Exporter 接口,后续支持 PDF、CSV、JSON 都走同一套调用链路
- 避免 if-else 判断类型后执行不同逻辑(如 if (type.equals("vip")) {...} else if (type.equals("normal")) {...}),换成策略映射或工厂获取
里氏替换与依赖倒置:一起用才真正起效
LSP 不是“能编译通过就行”,而是子类替换父类后,调用方不用改任何代码、不加任何判断,行为依然正确。DIP 是让这种替换成为可能的基础设施。
立即学习“Java免费学习笔记(深入)”;
- 父类方法声明抛出 IOException,子类重写时不能改成抛 RuntimeException;否则上层 try-catch 会失效
- 不要让子类重写后语义反转:父类 withdraw() 表示扣款成功,子类不能重写成“余额不足时静默返回”,而应统一抛异常或返回 Result 对象
- 依赖倒置落地很简单:Service 层变量声明用 UserService(接口),注入时才传入 JdbcUserServiceImpl;单元测试可轻松换 Stub 实现
接口隔离与迪米特法则:面向调用方设计接口
ISP 关注“别人怎么用你”,LOD 关注“你该怎么找别人”。两者都指向减少隐式耦合。
- 别写一个 UserService 接口,塞进 login()、resetPassword()、exportData()、sendPromotion();按场景拆成 UserAuth、UserAdmin、UserMarketing
- 一个类要用到另一个类的功能,尽量只通过它直接依赖的对象获取,不要跨级访问。例如:order.getCustomer().getAddress().getCity() 违反 LOD;应在 Order 或 Customer 上提供 getCity() 封装
- 第三方 SDK 调用(如微信支付 SDK)不要直接暴露给业务层;包一层自己的 WechatPayClient 接口,屏蔽内部参数组装与异常转换细节


















