Java设计模式实战:23种模式核心解析与高频场景代码示例
发布时间:2026/10/6 10:00:57 作者:尧图编辑部 阅读量:1,286

1. 开篇Java 设计模式到底值不值得啃先说个让人扎心的事实你会发现身边总有人写了三五年 Java代码还是“一个方法走天下”把十几种业务逻辑硬塞进同一个 if-else 结构里。而设计模式就是专门治这种“代码坏味道”的。所谓 Java 设计模式本质上是前人总结出来的“标准答案”——当你面对对象创建、结构组织、行为协作这三类问题的时候23 种经典方案基本能覆盖绝大多数日常业务开发场景。今天这篇我会避开教科书式说教直接以实际业务开发视角来拆这 23 种设计模式告诉你每个模式解决什么问题、什么时候千万别用、怎么和 Spring 这类主流框架融合。适合三类读者一是刚学完 Java 语法想去了解设计模式的小白二是有工作年限但代码被吐槽“可维护性差”的业务开发三是准备面试想系统梳理 Java 设计模式知识点的人。文章较长建议先收藏再慢慢消化。2. 23 种设计模式全景先看地图再上山2.1 三种分类背后的本质逻辑很多人一上来就背“创建型 5 个、结构型 7 个、行为型 11 个”背完就忘因为没搞懂这三分法到底在切什么角度。其实很简单你顺着软件开发的生命周期想写代码第一步是创建对象创建型第二步是把类和对象组合成更大的结构结构型第三步是让这些对象在运行时相互协作行为型。设计模式这三大分类本质就是在回答“对象怎么来、怎么摆、怎么动”这三个问题。拿盖房子打比方创建型模式是解决房子怎么盖出来的对应施工队伍怎么进场干活结构型模式是解决户型怎么布局对应承重墙、隔断、楼梯怎么安排行为型模式是解决住户之间怎么互动对应家庭成员分工协作的规则。这样一映射就再也不会把“工厂模式”和“适配器模式”混为一谈了。2.2 23 种模式清单速览在深入实战之前先用一张表把 23 种模式盘点清楚。这张表建议收藏面试前扫一眼就能快速唤醒记忆。分类模式名称核心解决的问题典型业务场景创建型单例模式全局只有一个实例配置管理器、线程池、连接池、Spring Bean创建型工厂方法由子类决定实例化哪个类日志记录器、文档转换器创建型抽象工厂创建一族相关对象跨平台 UI 控件、数据库访问族创建型建造者模式分步骤构造复杂对象订单 DTO、请求参数对象构造创建型原型模式通过复制现有对象创建新对象复杂报表模板复制、缓存克隆结构型适配器模式让不兼容的接口协同工作第三方短信 SDK 适配、老系统接口兼容结构型桥接模式抽象与实现分离消息发送方式扩展、多维度分类服务结构型组合模式树形结构统一处理菜单树、组织架构树结构型装饰器模式动态增强对象功能IO 流包装、日志增强、权限补充结构型外观模式给复杂子系统提供统一入口用户下单门面、支付聚合接口结构型享元模式共享细粒度对象降低内存字符串常量池、Integer 缓存结构型代理模式控制对目标对象的访问AOP、延迟加载、远程代理行为型职责链模式多个处理者依次处理请求审批流、敏感词过滤链行为型命令模式请求发送者与执行者解耦事务回滚、操作记录、宏命令行为型解释器模式定义语言并解释执行SQL 解析、规则引擎表达式行为型迭代器模式统一遍历集合的方式Java 容器遍历、自定义集合遍历行为型中介者模式简化对象之间的网状交互MQ 消息中间件、聊天室中心服务器行为型备忘录模式保存并恢复对象状态草稿箱、浏览器后退、游戏存档行为型观察者模式状态变化通知多个依赖对象下单后触发短信、优惠券、库存行为型状态模式状态切换驱动行为变化订单状态流转、审批状态机行为型策略模式算法族封装并可替换会员折扣、支付方式、排序算法行为型模板方法定义骨架子类实现细节数据导入、报表生成、订单处理流程行为型访问者模式不修改元素但增加新操作语法树分析、报表统计不同数据节点这张表看明白之后接下来我会挑业务开发中出现频率最高的 7 种模式手把手带你把代码写出来。剩下的 16 种我也会在第 5 部分给出速查判断逻辑保证你遇到对应场景时能想到用它。3. 实战业务开发中最高频的 7 个模式3.1 单例模式别让每个线程都 new 一个新对象单例模式是设计模式里“看起来最简单写错的人最多”的一个。业务开发里最常见的单例使用场景就是配置文件管理器、线程池、数据库连接池以及 Spring 中默认的单例 Bean。单例的核心诉求是一个 JVM 进程内某个类只能有一个实例并且要提供一个全局访问点。很多初学者写的懒汉式单例是直接在 getInstance 上加 synchronized这样没问题但是浪费性能每次调用都要经历锁竞争而实际上实例创建完以后根本不需要同步。更标准的写法是双重检查锁加 volatile。public class ConfigManager { private static volatile ConfigManager instance; private MapString, String configMap; private ConfigManager() { configMap loadFromConfigFile(); } public String get(String key) { return configMap.get(key); } public static ConfigManager getInstance() { if (instance null) { synchronized (ConfigManager.class) { if (instance null) { instance new ConfigManager(); } } } return instance; } }需要说明的是那个 volatile 为什么必不可少。instance new ConfigManager()这一步在 JVM 层面不是原子操作它分成了分配内存、初始化对象、把引用指向内存地址三步编译器和 CPU 可能进行指令重排。不加 volatile极端情况下线程 A 先完成引用赋值但对象还没完全初始化线程 B 进来自检发现 instance 不为 null 就直接拿去用轻则拿到半成品对象重则直接抛空指针。这个坑在面试中几乎是必问题实际生产环境也确实出现过代码里还是要老老实实写上。不过从 Java 5 之后还有更省心的方案枚举单例。public enum ConfigManager { INSTANCE }天然线程安全且防反射攻击。业务代码里我建议能枚举就枚举简洁到极致。但也要提醒一句单例模式最大的问题不是写法而是被人滥用。如果把有状态的数据放进去比如把用户的登录信息塞进全局单例 Map并发场景下你会死得很难看。单例只适合存无状态的工具类、配置信息这个边界要守住。3.2 工厂模式把 new 对象的脏活累活集中起来工厂模式在业务代码里的出场率极高尤其是做支付、短信、消息推送这类多渠道对接的系统。它的价值说白了就是一件事让调用方不直接 new 对象而是把创建逻辑集中到一个工厂里。这样做的好处有两个一是创建对象时的复杂初始化逻辑不用散落在业务代码各处二是以后新增渠道只需要加工厂里的分支调用方代码一行都不用改。简单工厂是最入门的写法本质上就是用 if-else 或 switch 返回不同实现类严格来说它不算 GoF 定义的模式但在中小型项目里非常实用。来看一段支付渠道的简单工厂实现。public interface PayChannel { void pay(PayRequest request); } public class AliPayChannel implements PayChannel { public void pay(PayRequest request) { // 调用支付宝 SDK } } public class WeChatPayChannel implements PayChannel { public void pay(PayRequest request) { // 调用微信 SDK } } public class PayChannelFactory { private static final MapString, PayChannel CHANNEL_MAP new HashMap(); static { CHANNEL_MAP.put(ali, new AliPayChannel()); CHANNEL_MAP.put(wechat, new WeChatPayChannel()); } public static PayChannel getChannel(String channelCode) { PayChannel channel CHANNEL_MAP.get(channelCode); if (channel null) { throw new IllegalArgumentException(不支持的支付渠道: channelCode); } return channel; } }这段代码在真实项目中特别常见用 Map 代替 if-else 本身就是一种解耦思想新增渠道只需要往 Map 里 put 一个实现类调用方永远只依赖 PayChannel 接口和工厂类。再往上进阶就是工厂方法模式把创建动作延迟到子类以及抽象工厂模式创建一族相关对象。实际业务中抽象工厂用得少因为大多数业务系统的产品族概念不强如果你在做跨平台 SDK比如一套 UI 同时支持移动端和桌面端抽象工厂才是正解。工厂模式和 3.3 要说的策略模式经常搭配使用策略负责“定义算法族”工厂负责“根据条件拿到对应算法”。这套组合拳在业务开发中的威力非常大值得反复练习。3.3 策略模式消灭业务代码里的 if-else 连招策略模式可以说是 Java 业务开发里“性价比最高”的模式因为它的出现直击痛点多重条件分支代码又长又难看改一处可能引发连锁错误。比如会员系统里不同会员等级的打折逻辑、订单系统里不同支付方式的手续费计算很多人第一版代码都是这么写的。if (gold.equals(level)) { amount amount.multiply(new BigDecimal(0.8)); } else if (silver.equals(level)) { amount amount.multiply(new BigDecimal(0.9)); } else if (normal.equals(level)) { amount amount.multiply(new BigDecimal(1)); }这种写法的问题在于每次加一个会员等级就要改这段业务代码改多了就会漏而且这是策略模式的典型反面教材。正确的思路是定义策略接口每个等级一个实现类再用一个上下文容器管理这些策略。public interface MemberLevelStrategy { String getLevelCode(); BigDecimal discount(BigDecimal amount); } Component public class GoldMemberStrategy implements MemberLevelStrategy { public String getLevelCode() { return gold; } public BigDecimal discount(BigDecimal amount) { return amount.multiply(new BigDecimal(0.8)); } } Component public class SilverMemberStrategy implements MemberLevelStrategy { public String getLevelCode() { return silver; } public BigDecimal discount(BigDecimal amount) { return amount.multiply(new BigDecimal(0.9)); } }策略有了关键是容器怎么拿到对应的策略实现。在 Spring 项目里有个非常优雅的写法直接把所有策略注入到一个 Map 里key 就是策略的标识。Service public class MemberLevelStrategyContext { private final MapString, MemberLevelStrategy strategyMap; public MemberLevelStrategyContext(ListMemberLevelStrategy strategies) { this.strategyMap strategies.stream() .collect(Collectors.toMap(MemberLevelStrategy::getLevelCode, s - s)); } public BigDecimal calculate(String levelCode, BigDecimal amount) { MemberLevelStrategy strategy strategyMap.get(levelCode); if (strategy null) { throw new IllegalArgumentException(未知会员等级: levelCode); } return strategy.discount(amount); } }这个写法的巧妙之处在于以后新增一个会员等级只需要新写一个策略类并加上 Component 注解Spring 会自动把它加进 List容器无需任何修改。这就是传说中的开闭原则也是代码质量的直接体现。我在实际项目里用这招重构过一个 PaymentStrategyContext把原来 30 个 if-else 分支压成了 12 个策略类代码量没少多少但可读性和可维护性完全不是一个量级。这里有个坑要提醒策略类如果本身带状态就麻烦了。比如把一个可变对象塞进策略中多个线程共用可能导致数据串线。写策略类时一定保证无状态所有的输入通过参数传入这样策略才能安全地被所有线程共享。3.4 模板方法模式流程骨架固定细节灵活下放模板方法和策略模式有点神似但应用场景完全不同。模板方法解决的是“流程步骤固定具体实现可变”的问题核心做法是在抽象类里把不可变的算法框架写死把可变步骤声明为抽象方法交给子类实现需要时再定义一些“钩子方法”供子类选择性覆盖。业务开发里模板方法最常见的场景就是各种数据导入导出、批量任务、审批流程。拿数据导入举例不管导入的是商品数据还是用户数据流程永远都是这三步解析文件、校验数据、入库保存。但每一步的具体实现完全不同把这三步写成模板能避免每个导入任务都重复一遍流程控制代码。public abstract class AbstractDataImportTemplate { public final void importData(InputStream in) { ListString rawList parseFile(in); ListObject validList validateData(rawList); saveData(validList); afterImport(validList); } protected abstract ListString parseFile(InputStream in); protected abstract ListObject validateData(ListString rawData); protected abstract void saveData(ListObject validData); protected void afterImport(ListObject validData) { System.out.println(导入完成默认记录日志); } }子类只需要关注自己那部分逻辑比如商品导入实现类只需要实现 parseFile、validateData、saveData 三个方法即可。为什么这里用抽象类而不是接口因为模板方法的核心是两个关键词复用骨架和限制流程。抽象类可以直接写公共逻辑同时用 final 修饰主流程防止子类破坏步骤顺序这是接口做不到的。模板方法和策略模式的区分记住了模板方法倾向于解决一件事的流程骨架统一策略倾向于一类算法的动态选择。如果你发现多个业务方法都长着同一副流程骨架只是中间某几步不一样优先考虑模板方法如果你发现一个方法里有多套算法要按条件选优先考虑策略模式。3.5 观察者模式把“下单后要通知谁”彻底解耦电商系统里下单后的处理清单往往很长发短信、扣库存、发优惠券、推送 App 通知、给运营人员发站内信、更新统计数据。很多第一版代码写来写去就成了“订单服务类一肩挑”方法里洋洋洒洒五十行后面每加一个需求都要改一次这个核心类。观察者模式就是干这个的当某个对象状态发生变化时自动通知所有注册的依赖对象。Java 里观察者模式在业务代码里的落地最优雅的方式就是 Spring 的事件机制。先定义一个事件类。public class OrderCreatedEvent extends ApplicationEvent { private final Long orderId; private final Long userId; private final String mobile; public OrderCreatedEvent(Object source, Long orderId, Long userId, String mobile) { super(source); this.orderId orderId; this.userId userId; this.mobile mobile; } // getter 省略 }然后订单服务只需要一行代码发布事件Service public class OrderService { Autowired private ApplicationEventPublisher eventPublisher; public void createOrder(OrderCreateDTO dto) { // 订单核心逻辑 Long orderId saveOrder(dto); eventPublisher.publishEvent(new OrderCreatedEvent(this, orderId, dto.getUserId(), dto.getMobile())); } }订阅方的每个监听器各管一摊Component public class SmsListener { EventListener Async public void onOrderCreated(OrderCreatedEvent event) { // 发送短信 sendSms(event.getMobile(), 您的订单已创建); } } Component public class CouponListener { EventListener Async public void onOrderCreated(OrderCreatedEvent event) { // 发放优惠券 grantCoupon(event.getUserId()); } }这样一来订单服务不需要知道到底谁关心这个事件后续新增“下单后赠送积分”只需要再加一个监听器核心类一行不动。在 Spring 中我还习惯给监听方法加上 Async 注解把短信、推送这类耗时操作丢到异步线程池执行避免拖慢主链路。要特别注意的是加 Async 后监听器的异常默认不会抛回主线程所以异步监听方法内部务必要自己做好 try-catch 和日志记录否则失败了你可能完全无感知。观察者模式看似简单实际设计时最需要思考的其实是两个问题监听器之间有没有必要保证顺序监听器执行失败要不要影响主流程常规方案是即时通知且失败必须回滚的场景用同步事件通知类场景用异步事件重要消息用消息队列做削峰填谷。3.6 建造者模式参数一多构造函数没法看了程序员每天写的东西里最容易爆炸的东西就是 DTO 和请求参数对象。当一个对象的构造参数超过四五个构造函数调用处就变成了灾难传参顺序稍微一错数据就静默传错位置。我见过一个老项目里有个 RequestDTO 构造函数有 9 个参数调用处常年配着大段注释凡是接触过的同事都在骂。建造者模式解决的就是这种场景它提供了一种链式调用的方式每个参数名称自解释顺序无所谓而且可以灵活跳过不需要的属性。Java 业务开发里最省事的就是用 Lombok 的 Builder 注解。Builder public class OrderCreateRequest { private Long userId; private Long productId; private String payChannel; private String address; private BigDecimal amount; }调用处代码瞬间可读性拉满OrderCreateRequest request OrderCreateRequest.builder() .userId(1001L) .productId(8866L) .payChannel(ali) .amount(new BigDecimal(199.00)) .build();也许有人觉得建造者模式和工厂模式容易混核心区别其实很清晰建造者模式关注对象的构建过程是“分步骤精心组装一个复杂对象”工厂模式关注创建结果本身是“直接拿一个现成的对象”。Spring 源码里大量使用建造者模式比如 BeanDefinitionBuilder、UriComponentsBuilder都是参数复杂而选择用链式构造的典型。如果项目里用不了 Lombok手写建造者模式也不难一个静态内部类 Builder成员变量和外部类一致每个方法返回 this最后 build 方法把值赋给新对象。这种代码没什么技术含量但对代码阅读体验的提升立竿见影。3.7 代理模式不侵入业务代码悄悄把功能给加了代理模式在 Java 领域有个地位极高的应用Spring AOP。事务管理、日志记录、权限校验、缓存处理这些横切逻辑正是通过动态代理织入业务方法的。这个模式的核心是不修改目标类源码而是通过创建一个代理对象来控制对目标对象的访问。JDK 动态代理基于接口写法非常轻量来看一个给业务方法加日志的典型案例。public class LogProxy implements InvocationHandler { private final Object target; public LogProxy(Object target) { this.target target; } Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long start System.currentTimeMillis(); Object result method.invoke(target, args); long cost System.currentTimeMillis() - start; System.out.println(method.getName() 耗时 cost ms); return result; } public static T T createProxy(T target, ClassT interfaceType) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), new Class[]{interfaceType}, new LogProxy(target)); } }实际业务中很少有人手动写这种代码因为 Spring 的 AOP 已经把这层细节隐藏掉了。但你至少要知道JDK 动态代理要求目标类实现接口如果目标类没有接口Spring 会自动改用 CGLIB通过生成子类的方式来代理。老面试题经常问这两种方式区别本质上就是接口驱动和继承驱动的差异。代理模式在业务开发中极少单独手写更多是作为理解 Spring AOP 底层原理的知识储备。4. 剩下 16 个模式一张表分清“什么时候该想起它”除了上面 7 个高频实战模式其余 16 种模式在真实业务项目里的出场频率略低但并不意味着可以忽略。应对的办法是不用把每个模式的实现细节都背熟但必须知道每个模式是解决什么问题而生的遇到对应场景时能想起它再翻书查实现细节就足够了。4.1 结构型模式速查与判断逻辑模式场景识别特征一句话落地方案适配器模式对接第三方服务方法签名对不上写一个 Adapter 类实现自己的接口内部转调第三方 SDK桥接模式一个业务类有两个维度的变化用组合替代继承比如不同类型消息 不同发送渠道组合模式数据天然成树形结构定义节点和叶子统一接口递归处理子节点装饰器模式要给对象动态叠加多种功能用包装类一层层包裹原对象比如 IO 流外观模式子系统众多调用方只需要一个统一入口写一个 Facade 类编排子系统方法享元模式大量重复小对象吃内存创建对象池相同的对象复用同一实例适配器模式我要多说一句它是老系统改造和新系统对接的救星。比如说公司老系统的用户接口返回的是name: 张三新系统需要的是fullName: Zhang San不需要改老系统代码写一个适配器把老接口返回值转换成新接口格式就行。很多日常开发里的“封装一层”其实就是适配器模式只不过很多人没意识到自己已经在用了。4.2 行为型模式速查与判断逻辑模式场景识别特征一句话落地方案职责链模式一个请求要经过多个处理器依次过滤每个处理器持有下一个处理器的引用流水线处理命令模式要把“执行动作”作为对象传递或存储把每个操作封装成类放进队列或用于事务回滚解释器模式需要解析自定义语法规则定义语法表达式建抽象语法树解析一般项目慎用迭代器模式要统一遍历不同集合结构Java 自带的 Iterator 就是典型实现自定义集合实现该接口即可中介者模式多个对象互相直接引用导致耦合严重引入一个中介类集中协调通信类似消息队列的脑子备忘录模式需要支持撤销和恢复把状态快照存起来实现备份和回滚状态模式对象行为随内部状态改变而改变状态抽象为接口每个状态一个实现类状态类负责切换访问者模式对象结构稳定但操作频繁扩展在不改元素类的前提下定义新访问者操作复杂度较高这里最容易在面试中出彩的其实是状态模式因为订单状态机是电商业务的典型需求。你会发现订单从待支付、已支付、已发货到已完成每个状态下能做的操作截然不同用状态模式可以让每个状态类自己决定“当前状态下能否发货、能否退款”替代一大片状态机 if-else。职责链模式也有很高的实战价值比如审批流中经过项目经理、部门经理、CTO 逐级审批每个审批人只关注自己能批的金额区间批不了就传给下一个。5. 设计模式的使用边界别为了模式而模式5.1 判断是否该用模式的三个标准学了设计模式之后很多人的第一反应是想把所有代码都套上模式这种“手里有锤子看什么都像钉子”的状态非常危险。我在 review 代码时见过一个订单创建流程愣是叠加了工厂加策略加模板加观察者加代理五层套娃最后那个类上百行项目里没人敢改。所以要记住一个冷酷的事实模式是武器不是枷锁滥用模式比不用模式更灾难。判断一个场景该不该套模式私藏的三个标准第一代码里是否存在明确的“变化点”比如支付渠道要扩展、会员折扣要调整有变化点才有抽象的意义第二当前项目中是否会有人长期维护这段代码做一次性脚本时谈模式纯属浪费时间第三团队同学能否理解这个模式实验室里写一个高深模式然后留下团队大眼瞪小眼那就是技术债。最朴素的建议是模式先用在已有重复代码的地方做重构而不是在写新功能时强行往里面塞。5.2 常见反模式与踩坑实录把模式用错的姿势很多我踩过或看到同事踩过的坑值得记一下。单例里放可变状态是头号公害有同事把用户信息塞进全局单例 Map结果用户 A 的下单请求偶尔串到用户 B 的订单上排查了两天才定位到是单例共享变量导致线程安全问题策略类不小心带了成员变量作为缓存多个线程共用同一实例导致计算混乱模板方法里主流程忘了加 final子类重写了整个骨架模板的约束意义名存实亡。还有一类错误是把多个模式强行叠加让代码变成“套娃迷宫”。一个销售数据查询方法先走工厂拿服务、再走策略选算法、外面套上装饰器做缓存、还挂个代理做埋点阅读者想看查找逻辑得跑四个类文件。这种代码的典型特征是类很多但每个类只有几行调用关系要画半天图。出现这种情况说明当初做设计时只想着“用模式”而没想着“解决什么实际问题”。设计模式是让代码更好理解的手段不是目的。我自己重构时有一条铁律如果某个模式套完之后解释这段代码功能需要超过三句话那就别这么干。5.3 重构案例把 600 行 if-else 订单处理拆成策略加模板分享一个真实重构案例某售后订单处理模块最初一个大方法里包含普通订单、秒杀订单、兑换订单三种类型每种类型内部又有已支付、未支付、已发货等分支总行数逼近 600 行加一个新玩法要在这团乱麻里找位置下刀。经过分析发现订单处理的流程骨架是一致的只是校验规则和执行细节不同于是用模板方法加策略模式做了重构。先定义处理器的统一骨架public interface OrderProcessor { int getOrderType(); void process(OrderContext context); } public abstract class AbstractOrderProcessor implements OrderProcessor { Override public final void process(OrderContext context) { validate(context); doProcess(context); afterProcess(context); } protected abstract void validate(OrderContext context); protected abstract void doProcess(OrderContext context); protected void afterProcess(OrderContext context) { context.markProcessed(); } }再让每种订单类型各写一个处理器继承骨架比如秒杀订单的校验会额外检查库存扣减兑换订单的校验会检查积分余额。最后用一个工厂维护类型编码和处理器映射调用方只需要一行代码。public class OrderProcessorFactory { private static final MapInteger, OrderProcessor PROCESSOR_MAP new HashMap(); static { PROCESSOR_MAP.put(1, new NormalOrderProcessor()); PROCESSOR_MAP.put(2, new SeckillOrderProcessor()); PROCESSOR_MAP.put(3, new ExchangeOrderProcessor()); } public static OrderProcessor getProcessor(int orderType) { return PROCESSOR_MAP.get(orderType); } }改造后的代码量并没有减少太多但结构发生了质变新增一个订单类型只需要新增一个处理器类并注册到工厂原来的代码一行不用动。核心业务逻辑从 600 行的泥潭里解放出来每个处理器类被压缩到 50 行上下读代码的人只需要看类名就明白这个类型做了什么。这就是设计模式对“代码质量”最实打实的贡献。6. 零基础到精通的进阶路线与面试突围6.1 五个阶段吃到透学习设计模式最忌原地背概念我的路线建议分五步走。第一步先把 23 种模式的分类和一句话用途过一遍形成全景地图不需要理解深度第二步进入动手阶段每种模式用 Java 写一个最小可运行 Demo比如单例写双重检查锁、策略写一个打折计算器第三步是项目找茬阶段打开 Spring、MyBatis、JDK 源码找到这些模式在真实框架中的影子比如 Spring 的 TransactionTemplate 是模板方法MyBatis 的 SqlSessionTemplate 是模板方法加代理JDK 的 Integer 缓存是享元第四步拿自己的老项目开刀找几个长方法用合适的模式重构不追求一次到位重点是体会“重构前后代码气质的变化”第五步就是输出总结把学到的模式结合自己的业务场景写成笔记。6.2 面试时这么讲至少加分 30%Java 设计模式是面试中的常驻题目但大多数人答得像背课文把定义背一遍再来个例子。真正让面试官满意的回答是“场景驱动”的先说出你遇到的什么问题再说为什么选这个模式最后讲清楚带来的收益。比如被问到策略模式一个高分回答模板是有次订单模块折扣逻辑堆了十几个 if-else加需求容易改漏我用策略模式把每个等级拆成独立类配合 Spring 注入把所有策略放到一个 Map后续新增等级不需要改旧代码。你看这段回答里有场景、有方案、有收益比任何教科书定义都有说服力。高频面试题走一遍单例为什么要用 volatile 加双重检查工厂方法和抽象工厂的区别策略模式和模板方法的区别代理模式中 JDK 动态代理和 CGLIB 的区别Spring 哪里用了观察者模式。核心思路永远是先摆场景再讲模式最后落到可维护性。设计模式面试考察的从来不是记忆力而是你有没有在真实代码里用过它、愿意思考它背后的取舍。把上面这 7 个高频实战模式配合真实业务例子练熟面试就稳了。7. 一点个人体会我工作这些年最有价值的一次代码能力跃迁不是学会了某个新框架而是把设计模式真正用进日常业务开发。开始刻意使用模式后的第一周我的代码 review 被打回次数变多了因为一开始常常过度设计一个季度之后再回看同事评价从“看不懂你在写什么”变成了“结构蛮舒服的”。设计模式不是考试题它是你和未来接手代码的人之间的默契。这篇文章写到的 23 种模式哪怕你只把高频的 7 种吃透再配合一张速查表鉴别低频模式日常 Java 业务开发就已经完全够用了。最后再分享一个小技巧写完代码过一天再读一遍凡是觉得“这里怎么这么绕”的位置多半就是可以引入模式或拆分的信号。