设计模式六大原则,带你看懂编程的底层逻辑
设计模式六大原则是构建高质量代码的基石,但很多教材中的例子过于抽象,导致理解困难。本文将通过生活化场景和实际代码案例,重新解读这些原则的本质,力求让你豁然开朗。
一、单一职责原则(SRP)[各司其职,简洁高效]
定义:对一个类而言,应该只有一类功能相关的职责
核心思想:避免“大杂烩式”代码,就像餐厅服务员不应该同时负责点菜、炒菜和结账。
经典案例:
假设有一个UserService
类,同时处理用户登录、注册、发送邮件和记录日志。当邮件服务提供商更换时,修改邮件发送逻辑可能会意外影响登录功能。
改进方案:
拆分成四个独立模块:
LoginService
:处理登录RegisterService
:处理注册EmailService
:发送邮件LogService
:记录日志
好处:修改邮件服务时,完全不影响其他功能,测试和维护更聚焦
二、开闭原则(OCP)[拥抱扩展,拒绝修改]
定义:对扩展开放,对修改关闭。
核心思想:像乐高积木一样拼装新功能,而不是拆掉旧模块。
经典案例:
电商订单系统需要支持多种折扣策略(普通用户、VIP、节日促销)。如果直接在订单类中写if-else
判断用户类型,每次新增策略都要修改原有代码。
改进方案:
- 定义接口
DiscountStrategy
,包含calculateDiscount
方法。 - 实现
VipDiscountStrategy
、FestivalDiscountStrategy
等具体策略。 - 订单类通过依赖注入使用策略,新增策略只需扩展新类,无需修改原有逻辑
public class Order {
private DiscountStrategy strategy;
public Order(DiscountStrategy strategy) { this.strategy = strategy; }
public double calculatePrice(double originalPrice) {
return originalPrice * strategy.calculateDiscount();
}
}
三、里氏替换原则(LSP)[子类上位,无缝衔接]
定义:子类必须能完全替代父类,且不破坏程序逻辑。
核心思想:继承不是“为了复用代码”,而是“为了表达逻辑一致性”。
经典反例:
让Penguin
(企鹅)继承Bird
(鸟类),但Bird
有fly()
方法。企鹅不会飞,调用fly()
时抛出异常,这违反了父类契约。
改进方案:
- 拆分
Bird
为FlyingBird
和NonFlyingBird
- 企鹅继承
NonFlyingBird
,燕子继承FlyingBird
关键点:继承前必须确认“子类是否满足父类的所有行为约定”
四、依赖倒置原则(DIP)[面向抽象,解耦神器]
定义:高层模块不依赖底层实现,二者都依赖抽象。
核心思想:像使用手机充电器一样,只关心USB接口,不关心内部电路。
经典案例:
数据库访问层直接依赖MySQL驱动代码,切换成Oracle需要重写所有SQL语句。
改进方案:
- 定义接口
UserRepository
,声明save()
、findById()
等方法。 - 实现
MySQLUserRepository
和OracleUserRepository
。 - 业务逻辑层仅依赖
UserRepository
接口,数据库切换零影响
五、接口隔离原则(ISP)[按需定制,拒绝冗余]
定义:客户端不应被迫依赖它不需要的接口。
核心思想:不要逼用户买整个工具箱,而是按需选择螺丝刀或锤子。
经典反例:
一个多功能打印机接口Printer包含打印、扫描、传真方法。普通打印机只能打印,却被迫实现空扫描和传真方法。
改进方案:
拆分为三个接口:
Printable
:打印Scannable
:扫描Faxable
:传真
普通打印机只需实现Printable
,三合一设备实现全部接口
六、迪米特法则(LoD)[保持距离,降低耦合]
定义:一个对象应尽可能少了解其他对象。(只与“直接朋友”对话)
核心思想:像点外卖时,你只需要和外卖平台沟通,而不是直接联系厨师、骑手和餐厅老板。
经典案例:
经理需要统计员工工作量,若直接访问每个员工的WorkReport
对象,一旦员工数据结构变化,经理类需要同步修改。
改进方案:
- 经理类只与
TeamLeader
交互。 TeamLeader
封装统计逻辑,返回结果给经理。
// 错误实现:经理直接访问所有员工
manager.getEmployees().forEach(e -> e.getWorkReport().getHours());
// 正确实现:通过TeamLeader中介
manager.getTeamLeader().calculateTotalHours();
好处:员工数据结构变化时,只需修改TeamLeader
,经理类无需调整
总结
六大原则本质是解耦与抽象的平衡艺术:
- 单一职责与接口隔离控制代码粒度,避免“万能类”
- 开闭原则与依赖倒置通过抽象提升扩展性,适应需求变化
- 里氏替换与迪米特法则确保协作安全,降低耦合风险
推荐结合《漫画设计模式》中的趣味案例进一步理解,将抽象原则具象化为可落地的代码设计技巧。