藏在Java心脏里的23种设计模式:JDK源码中的设计模式

南春编程 2025-04-20 04:00:16

每个Java开发者都经历过这样的时刻:当你写下List list = new ArrayList()时,是否会好奇为何迭代器能“自动”遍历?当你调用Runtime.getRuntime()时,是否疑惑它为何总能返回同一个实例?这些看似简单的操作背后,藏着23种经典设计模式的精妙应用。 设计模式不是“花架子”,而是Java生态的DNA。从单例模式到代理模式,从迭代器到装饰器,JDK的每一行源码都在无声地诠释着软件设计的智慧。本文将带你潜入JDK的“心脏”,破解这些模式如何让Java在30年长跑中始终“稳如老狗”。

单例模式:唯一才是王道

核心作用:确保全局仅有一个实例,避免资源浪费与状态混乱。 JDK经典案例:

Runtime类:每个Java应用仅有一个运行时环境。源码中通过静态变量currentRuntime直接初始化实例,构造函数私有化。Javapublic Runtime { private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime() { return currentRuntime; } private Runtime() {} // 堵死外部new的路 } Logger日志类:日志系统全局只需一个控制中枢。

为何重要?

性能:避免重复创建对象(如数据库连接池)。安全:防止多实例导致状态冲突(如配置管理)。工厂模式:流水线上的对象制造

核心作用:将对象创建与使用解耦,应对复杂对象的“量产需求”。 JDK经典案例:

静态工厂:Integer.valueOf():根据数值返回缓存对象,避免重复创建(享元模式结合)。Calendar.getInstance():根据时区动态创建日历实例。抽象工厂:DocumentBuilderFactory.newInstance():生成不同XML解析器(如DOM、SAX)。

实战价值:

屏蔽底层差异:比如数据库驱动DriverManager.getConnection(),用户无需关心MySQL还是Oracle。灵活扩展:新增产品线只需扩展工厂,无需修改客户端代码。装饰器模式:给代码“穿马甲”

核心作用:动态添加功能,避免继承导致的类爆炸。

JDK经典案例:

IO流家族:JavaInputStream is = new FileInputStream("file.txt"); BufferedInputStream bis = new BufferedInputStream(is); // 加缓冲 DataInputStream dis = new DataInputStream(bis); // 加数据类型解析

设计精髓:

“包装即服务”——装饰器通过嵌套组合,让功能像乐高积木一样自由拼装。

适配器模式:让不兼容的接口“握手言和”

核心作用:充当“转接头”,适配新旧系统或第三方组件。 JDK经典案例:

Arrays.asList():将数组适配为List接口,使其支持集合操作。InputStreamReader:将字节流适配为字符流,解决编码差异。

现实映射: 就像用Type-C转接头连接旧手机,适配器让老代码无缝接入新体系。

迭代器模式:遍历的终极哲学

核心作用:统一集合遍历方式,隐藏底层数据结构。

JDK经典案例:

Collection.iterator():无论是ArrayList还是HashSet,统一用hasNext()和next()遍历。Enumeration与Iterator:旧版枚举器通过适配器模式兼容新版迭代器。

设计哲学:

“不要告诉我你的内部结构,我只要一个遍历器。”——封装让集合与遍历逻辑彻底解耦。

观察者模式:事件驱动的核心引擎

核心作用:实现一对多的消息通知机制。

JDK经典案例:

java.util.Observable:被观察者通过notifyObservers()通知所有监听者。Swing事件机制:按钮点击事件触发ActionListener回调。

应用场景:

GUI开发中的事件处理。微服务中的配置中心动态推送。代理模式:幕后英雄的操控术

核心作用:控制对象访问,增强功能(如日志、鉴权)。

JDK经典案例:

动态代理:Proxy.newProxyInstance()生成接口代理类,AOP的基石。RMI远程调用:本地存根(Stub)代理远程对象。

实战技巧:

性能监控:代理DAO层方法,统计SQL执行时间。安全校验:在代理层统一验证权限。组合模式:树形结构的万能钥匙

核心作用:用一致的方式处理单体与组合对象。

JDK经典案例:

Map.Entry接口:键值对作为整体参与Map操作,如HashMap.Node。Swing容器组件:JPanel可以嵌套其他JComponent。

设计隐喻:

“文件夹与文件都是‘资源’”——组合模式让递归处理变得自然。

策略模式:算法的自由超市

核心作用:定义算法族,使其可互换。

JDK经典案例:

Comparator接口:排序时传入不同比较器,实现升序、降序或多字段排序。线程池拒绝策略:AbortPolicy(直接拒绝)与CallerRunsPolicy(回退到调用线程)。

价值体现:

支付系统:根据用户选择切换支付宝、微信支付策略。风控引擎:灵活组合不同规则算法。模板方法模式:流水线上的标准化

核心作用:定义算法骨架,子类实现具体步骤。

JDK经典案例:

AbstractQueuedSynchronizer(AQS):acquire()方法定义获取锁流程,子类实现tryAcquire()。HttpServlet:service()方法路由GET/POST请求,子类重写doGet()或doPost()。

核心思想:

“大框架我定,细节你填”——模板方法平衡了复用与扩展。

今天先介绍10种模式。

模式不是银弹,而是思维地图

从Runtime的单例到IO流的装饰器,从集合的迭代器到AQS的模板方法,JDK的每一处设计都在诠释一个真理:优秀的代码不是偶然,而是模式的必然。

初阶:识模式,读源码。中阶:用模式,解难题。高阶:忘模式,创设计。

当你下次写下list.iterator()时,愿你能会心一笑——原来这行代码的背后,站着23位“设计巨人”。

0 阅读:8
评论列表
  • 不管。实用最重要。前几天分析Babel的XML文件,基本80.90M,遍历,我最后选择的还是firstChild,自己的问题自己懂,别人都是扯淡。