设计模式深度解析:从六大原则到Spring源码,面试通关全攻略
设计模式深度解析:从六大原则到Spring源码
一、为什么要学设计模式?
很多程序员对设计模式的认知停留在面试要考四个字,但设计模式真正的价值在于看懂优秀框架源码、写出可维护的代码、在团队协作中用统一语言沟通。
场景一:接手离职同事项目,类名满天飞但看不懂。
场景二:面试问Spring用了哪些设计模式,答不出来直接pass。
场景三:技术评审时if-else方案被否,不懂策略模式。
二、设计模式的本质
设计模式=建筑行业的标准图纸。六大设计原则是地基:单一职责、开闭原则、里氏替换、依赖倒置、接口隔离、迪米特法则。
策略模式=开闭+单一职责;工厂模式=依赖倒置+开闭;观察者=开闭+迪米特。三个层次:知道(背名字)→会用(掌握场景)→忘记(编码本能)。
三、核心模式实战
3.1 策略模式
定义DiscountStrategy接口 → 各策略类独立封装(VipDiscountStrategy、SuperVipDiscountStrategy)→ StrategyFactory管理路由。加新策略只需新建类加@Component注解,不修改原有代码,完美遵循开闭原则。
public interface DiscountStrategy { BigDecimal discount(BigDecimal originPrice); String getType(); } @Component public class VipDiscountStrategy implements DiscountStrategy { public BigDecimal discount(BigDecimal originPrice) { return originPrice.multiply(new BigDecimal("0.8")); } public String getType() { return "vip"; } } @Component public class DiscountStrategyFactory { private final Map<String, DiscountStrategy> map = new HashMap<>(); public DiscountStrategyFactory(List<DiscountStrategy> strategies) { for (DiscountStrategy s : strategies) map.put(s.getType(), s); } public BigDecimal calc(String type, BigDecimal price) { DiscountStrategy s = map.get(type); return s == null ? price : s.discount(price); } }3.2 观察者模式
Spring事件机制就是观察者模式:OrderPaidEvent → SmsListener/PointsListener/InvoiceListener各监听 → OrderService完全不知道谁在监听。加CouponListener零改动。精髓:解耦发布者和订阅者。
public class OrderPaidEvent extends ApplicationEvent { private final Long orderId; public OrderPaidEvent(Object source, Long orderId) { super(source); this.orderId = orderId; } } @Component public class SmsListener { @EventListener public void handle(OrderPaidEvent event) { /* 发短信 */ } } @Component public class PointsListener { @EventListener public void handle(OrderPaidEvent event) { /* 发积分 */ } }3.3 单例模式
双重检查锁定必须加volatile(禁止指令重排序)。集群环境单例无意义需分布式锁(Redis/ZK)。Spring Bean是IoC容器级别单例(同BeanName唯一)vs 设计模式JVM级别单例。
四、Spring用了哪些设计模式(面试必考)
| 设计模式 | Spring中的应用 | 面试要答出 |
|---|---|---|
| 工厂模式 | BeanFactory/ApplicationContext | IoC容器=工厂+单例池 |
| 单例模式 | Bean默认scope=singleton | 容器级别vs JVM级别 |
| 代理模式 | AOP动态代理(JDK/CGLIB) | @Transactional本质代理增强 |
| 模板方法 | JdbcTemplate/RestTemplate | 父类骨架子类步骤 |
| 策略模式 | Resource多种实现 | 同接口不同实现 |
| 观察者模式 | @EventListener | 事件驱动解耦 |
| 适配器模式 | HandlerAdapter | 统一处理不同Controller |
| 装饰器模式 | BeanDefinitionDecorator | 不改变原类动态增强 |
| 责任链模式 | Filter Chain | 请求依次经过处理器 |
五、避坑指南
| 坑 | 现象 | 正确做法 |
|---|---|---|
| 过度设计 | 3种if-else改成策略+工厂,20行变200行 | 变化点小于3且不频繁,if-else够用 |
| 为了模式而模式 | 先想用哪个模式再想解决什么问题 | 先分析问题再找对应模式 |
| 不理解意图 | 背了8种单例写法不知为什么 | 理解为什么比怎么写重要10倍 |
| 忽略原则 | 只学23种模式不懂六大原则 | 懂了开闭原则自己就能发明策略模式 |
| 模式滥用 | 所有地方都用单例/工厂/代理 | 每个模式增加类数量,滥用导致类爆炸 |
六、面试速查表
| 考点 | 频率 | 问法 |
|---|---|---|
| 六大原则 | 5星 | 说说开闭原则,举项目例子 |
| 策略模式 | 5星 | if-else太多怎么优化 |
| 单例模式 | 4星 | 双重锁定为什么加volatile |
| 工厂模式 | 4星 | 工厂和策略模式有什么区别 |
| 观察者模式 | 4星 | MQ和观察者模式有什么区别 |
| 代理模式 | 4星 | JDK动态代理和CGLIB区别 |
七、总结
设计模式核心不在背定义,在于理解设计原则和应对变化的思维。推荐路线:六大原则(3天)→高频6模式(1周)→Spring源码中的模式(2周)→工作中刻意练习。
