Java 23种设计模式全解析:面试与实战必备

在日常的开发过程中,我们经常会遇到代码结构混乱、难以维护的问题。这时候,设计模式就成了我们的救命稻草。今天,我想和大家系统地聊聊 Java 中的 23 种设计模式,不仅仅是枯燥的概念,更结合实际场景说说它们到底怎么用,以及在面试中如何得分。

为什么我们需要设计模式?

简单来说,设计模式是前人总结的“最佳实践”。它们不是具体的代码,而是一套被反复使用、多数人知晓的代码设计经验。使用设计模式的核心目的有三个:

  1. 可重用性:避免重复造轮子。
  2. 让代码更容易被他人理解:统一的模式让团队协作更顺畅。
  3. 保证代码可靠性:经过验证的结构自然更稳。

这 23 种模式通常分为三大类:创建型(5种)、结构型(7种)和行为型(11种)。下面我们逐一拆解。


一、创建型模式(Creational Patterns)

这类模式关注对象的创建过程,旨在将对象的创建和使用分离,降低系统的耦合度。

1. 单例模式

核心思想:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  • 应用场景:配置管理器、数据库连接池、日志记录器。
  • 实战注意:在多线程环境下,务必使用“双重检查锁”或“静态内部类”方式,避免产生多个实例。
    // 静态内部类方式(推荐)
    public class Singleton {
        private Singleton() {}
    
    

private static class Holder { private static final Singleton INSTANCE = new Singleton(); }

public static Singleton getInstance() { return Holder.INSTANCE; } } ```

2. 工厂方法模式

核心思想:定义一个创建对象的接口,但由子类决定要实例化的类是哪一个。

  • 应用场景:日志记录器(文件日志、数据库日志)、不同类型的数据库连接。
  • 优势:扩展性好,符合“开闭原则”,新增产品时只需新增一个具体工厂类。

设计模式分类图示

23种设计模式通常分为创建型、结构型和行为型三大类。

3. 抽象工厂模式

核心思想:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

  • 应用场景:跨平台的 UI 组件(如同时支持 Windows 和 Mac 风格的按钮和窗口)。
  • 区别:工厂方法模式是生产一个等级结构的产品,而抽象工厂模式是生产多个等级的产品族。

4. 建造者模式

核心思想:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

  • 应用场景:构建复杂的 HTML 对象、SQL 查询生成器、类似 Lombok 的 @Builder 注解。
  • 优势:客户端不必知道产品内部组成的细节,构建过程更灵活。

5. 原型模式

核心思想:通过复制现有的实例来创建新的实例,而不是通过 new 关键字。

  • 应用场景:创建成本较高的对象、通过深拷贝保护原对象。
  • 注意:Java 中需实现 Cloneable 接口,深拷贝时需注意引用类型成员变量的处理。

二、结构型模式(Structural Patterns)

这类模式关注类和对象的组合,通过继承或组合来构建更大的结构。

6. 适配器模式

核心思想:将一个类的接口转换成客户希望的另一个接口。

单例模式双重检查锁图示

单例模式在多线程环境下的实现方式对比。

  • 生活案例:电源插头转换器(两孔转三孔)。
  • 应用场景:老旧系统的接口对接、第三方库接口不兼容时。

7. 装饰器模式

核心思想:动态地给一个对象添加一些额外的职责,比生成子类更为灵活。

  • 应用场景:Java I/O 流中的 new BufferedReader(new FileReader(...))
  • 优势:不改变原有对象结构,扩展功能非常方便。

8. 代理模式

核心思想:为其他对象提供一种代理以控制对这个对象的访问。

  • 应用场景
    • 远程代理:RPC 调用。
    • 虚拟代理:图片延迟加载。
    • 保护代理:权限控制(如 Spring AOP)。

9. 外观模式

核心思想:为子系统中的一组接口提供一个一致的界面,定义一个高层接口,这个接口使得这一子系统更加容易使用。

  • 应用场景:复杂的库或 API 的入口类(如电脑启动时,一键开启 CPU、内存、硬盘等)。

10. 桥接模式

核心思想:将抽象部分与实现部分分离,使它们都可以独立地变化。

  • 应用场景:JDBC 驱动(Java 应用与不同数据库实现的解耦)、不同形状与不同颜色的组合。

11. 组合模式

核心思想:将对象组合成树形结构以表示“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性。

  • 应用场景:文件系统(文件夹和文件)、树形菜单。

12. 享元模式

核心思想:运用共享技术有效地支持大量细粒度的对象。

  • 应用场景:Java 中的 String 常量池、Integer 缓存(-128 到 127)、五子棋游戏中的棋子对象。
  • 优势:大幅减少内存中对象的数量,降低内存消耗。

三、行为型模式(Behavioral Patterns)

这类模式关注对象之间的通信、职责划分以及算法的封装。

13. 策略模式

核心思想:定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。

  • 应用场景:支付方式(微信、支付宝、银联)、排序算法选择、出行方式(骑车、打车、走路)。
  • 实战技巧:配合工厂模式或 Spring 的自动注入,可以非常优雅地消除代码中大量的 if-else

14. 观察者模式

核心思想:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

  • 应用场景:事件驱动系统(如 Vue 的数据双向绑定)、消息队列(如发布订阅模式)、Guava EventBus。

15. 模板方法模式

核心思想:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。

  • 应用场景:Servlet 的生命周期、Spring JdbcTemplate、业务流程固定的场景(如下单流程:校验->扣库存->生成订单)。

16. 责任链模式

核心思想:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

  • 应用场景:Web 过滤器链、审批流程(组长->经理->总监)、异常处理链。

17. 命令模式

核心思想:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。

  • 应用场景:GUI 按钮点击事件、撤销/重做操作。

18. 迭代器模式

核心思想:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。

  • 应用场景:Java 中的 Iteratorforeach 循环。

19. 中介者模式

核心思想:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用。

  • 应用场景:MVC 框架中的 Controller(C)、聊天室服务器。

20. 备忘录模式

核心思想:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。

  • 应用场景:游戏存档、文本编辑器的撤销功能。

21. 解释器模式

核心思想:给定一个语言,定义它的文法的一种表示,并定义一个解释器。

  • 应用场景:正则表达式引擎、SQL 解析器、XML/JSON 解析。
  • 注意:实际业务开发中较少使用,主要用于编译器开发。

22. 状态模式

核心思想:允许一个对象在其内部状态改变时改变它的行为。

  • 应用场景:订单状态流转(待支付->已支付->发货->完成/退款)、TCP 连接状态。

23. 访问者模式

核心思想:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

  • 应用场景:编译器(语法树分析)、XML 文档解析。

总结与建议

这 23 种设计模式并非都要死记硬背,理解其应用场景和解决的问题才是关键。

  1. 不要过度设计:如果是简单的业务逻辑,强行套用模式反而会让代码变得复杂晦涩。
  2. 多看源码:Spring、JDK 源码中到处都是设计模式的影子,比如 Spring 中用到了大量的工厂模式、代理模式和模板方法模式。阅读源码是学习最好的方式。
  3. 重构时引入:在代码 Review 或重构时,识别出“代码异味”(如大量的 if-else),再考虑用策略模式或工厂模式来优化。

希望这份总结能帮大家在日常 coding 和面试中更加游刃有余。你觉得哪种模式在实战中最难理解?欢迎在评论区讨论!

标签: none

AI Skills Smart Station on Nick Launches

评论已关闭