都说AI要替代程序员了可我自己在大量使用生成式AI辅助开发之后反而越来越觉得设计模式这东西比过去更重要了。原因很简单AI生成代码的速度越快代码腐烂的速度也越快。没有设计模式这把尺子AI生成的那堆“能跑”的代码三个月后就能把项目拖进泥潭。这个系列我想认真聊聊一个话题在生成式AI时代我们怎么重新理解和运用设计模式。这既不是照搬《Head First Design Patterns》的老调重弹也不是堆砌23个模式的教科书复读。我打算结合自己用生成式AI做实际项目的经验把设计模式当作一种“对话协议”和“架构约束”来用让AI生成的代码从一开始就具备良好的结构和可维护性。第一篇先打地基搞清楚设计模式的本质分类以及生成式AI时代设计模式为什么从“编码技巧”升级成了“必备生存技能”。适合正在用或准备用AI辅助写代码的开发者、想系统梳理设计模式的知识体系的人也适合那些被AI生成的烂代码坑过、想知道怎么抢救的人。1. 生成式AI爆火之后设计模式反而被低估了1.1 AI写的代码看着都能跑问题到底出在哪我先说个真实场景。上个月帮朋友review一个用AI辅助开发的电商项目代码量大概两万行前后花了三周。整体看下来功能齐了demo演示也没问题但当我看到核心订单模块的时候后脊梁发凉——一个订单服务类干了一千多行里面塞了促销计算、库存扣减、支付回调、消息推送、日志记录甚至还有Excel导出。一个方法里连环嵌套了六个if-else判断不同支付渠道的回调处理。我试着改其中一个支付渠道的逻辑改了十分钟跑了三次测试全挂。这就是典型的“AI生成代码综合征”你让AI写“订单处理逻辑”它非常忠实地把所有相关逻辑全部堆在一个方法里。它不知道你的项目里有没有策略模式不知道支付渠道是不是应该用工厂来管理更不知道这段代码三个月后要被哪些模块复用。AI确实能快速生成大量可用代码但它缺乏对软件长期演进的判断力——而这个判断力恰恰是设计模式存在的意义。设计模式本质上是一套经过实战检验的“协作契约”。它不只是解决“怎么写出某段功能”而是解决“这段代码和其他代码怎么配合、将来怎么扩展、出了问题怎么排查”。生成式AI把编码的门槛拉低了但架构设计的门槛反而更高了——因为现在人人都有了一个“无限加班、无限产出的初级程序员”代码量爆炸式增长架构约束的重要性比任何时候都突出。1.2 为什么说生成式AI时代更需要设计模式过去我们靠代码审查来控制代码质量现在AI一小时生成的代码人工审查根本看不过来。设计模式在这里扮演的角色完全变了它不再只是“面试题里的标准答案”而是一种可执行的质量过滤器。我自己实测下来同样的需求给AI加一条“使用策略模式处理促销计算”的约束和直接说“帮我写促销计算逻辑”生成的代码质量差距是质的。前者生成的是可扩展、可测试、职责清晰的代码后者多半是一个巨大的switch-case或者一堆if-else。这不是AI的能力差距而是你给它的“架构上下文”的差距。而且生成式AI本身也在逼我们重新思考模式。当你频繁地用AI生成代码时你会发现你其实是在用“提示词”做架构设计。提示词的结构、约束条件、上下文信息的组织方式本质上就是一种“对话模式”。模板方法模式、策略模式、观察者模式这些经典模式的思想完全可以映射到提示词工程里。这个映射关系我后面会专门展开讲。1.3 别被“设计模式过时论”带偏了网上一直有一种声音说设计模式是Java时代的古董现代开发用不着了。持有这种观点的人多半是把设计模式理解成了“某种代码写法”。单一职责、开闭原则、依赖倒置这些底层思想永远不过时。变的是实现载体以前用继承多态实现策略模式现在可以用函数式接口、可以用配置中心、可以让AI生成差不多的骨架再人工微调。所以这个系列聊的“生成式AI设计模式”不是否认经典而是把它们放在新工具、新工作流的语境里重新审视。经典模式是骨架生成式AI是加速器两者结合才是这个时代的高效开发方式。2. 先吃透设计模式的骨架分类与选择逻辑2.1 三种类型到底在解决什么本质问题设计模式的分类逻辑比记住23个名字重要一万倍。创建型、结构型、行为型这三大类对应的分别是三个最基础的问题对象怎么来、对象怎么组、对象怎么聊。创建型模式解决“怎么别用new用出一堆问题”。最朴素的需求是我不想在每个地方都直接new一个对象因为一旦构造逻辑变了所有调用方都要跟着改。工厂模式把“创建对象的时机和方式”收敛到一个地方单例模式保证全局只有一个实例建造者模式解决“对象参数太多、构造太复杂”的问题。在生成式AI辅助开发中创建型模式最大的价值是你只需要对AI描述“我想要一个可以创建不同支付渠道处理器的工厂”它就能生成相当标准的骨架代码而且这个骨架天然具备良好的扩展点。结构型模式解决“类和对象怎么组合才能既不僵硬又不松散”。适配器模式让不兼容的接口能协同工作装饰器模式给对象动态添加职责而没有继承的僵化外观模式给复杂子系统一个干净的门面。做AI辅助开发时最容易犯的错就是AI不知道你的项目里已经有了一套日志组件、缓存组件它可能会生成重复或者不兼容的实现。如果你在提示词里明确说明“使用外观模式封装现有的支付网关接口”AI生成的代码就会主动去适配你的项目结构而不是另起炉灶。行为型模式解决“对象之间的职责和协作怎么分配”。策略模式把算法族封装成可互换的策略对象观察者模式让状态变化能通知到所有关心它的对象模板方法模式把算法的骨架定死、把可变步骤留给子类。行为型模式是AI辅助编码中最容易被忽视、影响却最大的一类。因为AI特别擅长生成“功能正确但职责混乱”的代码行为型模式恰恰是职责划分的利器。2.2 一张表理清模式选型的核心依据我整理了一份简化版的选择逻辑不是让你背口诀而是给你一个快速判别的思路。你要解决的问题首选模式方向典型场景举例多个同类对象创建方式复杂或需要统一管理工厂模式、抽象工厂模式支付渠道、消息推送服务、数据库连接全局只需要一个共享实例单例模式配置管理器、线程池、缓存客户端对象构造参数过多、组合方式多变建造者模式复杂查询条件、报表配置、HTTP请求构建接口不兼容需要桥接适配器模式对接第三方SDK、老系统接口、不同版本API给对象动态加功能避免类爆炸装饰器模式日志增强、权限校验、数据脱敏一组算法/规则需要自由替换策略模式促销计算、运费计算、审批流程、风控规则一个对象状态变化需要通知多方观察者模式订单状态变更、消息通知、事件驱动架构算法骨架固定但有可变步骤模板方法模式数据导入流程、报表生成流程、批处理任务访问对象内部结构但不暴露内部细节迭代器模式遍历聚合对象、树形菜单、分页数据这个表看起来简单但实操中很有用。每次你要让AI生成代码之前先拿这个表对照一下需求把对应的模式关键词写进提示词里。AI生成的代码结构会有质的不同。2.3 记不住23个模式没关系记住这三条主线很多人在准备面试或者期末考试的时候试图把23种模式全部背下来然后画UML图结果一画就忘。我建议换个思路把模式按“变化点”来理解。变化点一创建对象的逻辑可能变。今天支付渠道只有微信和支付宝明天加了银联和PayPal你希望新增渠道的时候不改动业务代码只加一个新类。这就是创建型模式存在的理由。变化点二对象之间的连接方式可能变。你的系统要接一个新的短信供应商接口格式完全不同你不想为每个供应商都改一遍业务代码。这就是适配器、外观这些结构型模式的用武之地。变化点三对象的行为和协作规则可能变。双十一的促销规则、不同会员等级的折扣、不同地区的运费政策全都是会变的东西。策略模式负责把这些变化封装成独立的策略对象模板方法负责把不变的流程骨架定下来。理解了这三条主线你再去看任何一种设计模式都会觉得它只是“应对某种变化”的套路而已。这个认知框架也是后面跟生成式AI协作的基础——AI最擅长的事情就是根据变化点生成对应的扩展结构。3. 生成式AI时代设计模式的新角色从代码模板到对话协议3.1 为什么说提示词工程本身就是一种设计模式我在大量使用AI辅助编程之后发现一个很有意思的事情高效的提示词结构和经典设计模式的结构是高度同构的。你写提示词的时候如果每次都是“帮我写一个订单服务”AI不知道你的项目上下文只能从海量训练数据里猜一个“平均”的订单服务长什么样——结果就是那个一千行的上帝类。但如果你用“模板方法模式”的思路来组织提示词把不变的部分固化为固定的描述框架把变化的部分留给每次的具体需求AI输出的质量会稳定得多。我自己的提示词框架长这样背景这是一个基于Spring Boot的电商项目订单模块采用策略模式处理不同的促销活动。 需求新增一种“满300减50”的促销策略要求输入订单金额输出优惠金额。 约束策略类需要注册到现有的促销策略工厂中不允许修改订单服务的核心逻辑。 输出请生成策略类、工厂注册代码以及对应的单元测试。你可以看到这个提示词里没有一句废话。它告诉AI项目背景是什么、这个需求属于哪种模式、边界在哪里、输出物有哪些。AI拿到这个提示词不会瞎发挥而是严格地遵循你给的“算法骨架”去填充具体实现。这不就是模板方法模式的思想吗3.2 模式感知AI辅助开发的第一项基本功现在很多团队用AI辅助开发效率没有显著提升甚至代码质量下降核心原因就是缺少模式感知能力。什么叫模式感知就是你在向AI描述需求的时候脑海里已经有一个初步的架构判断这个需求适合用什么模式、边界在哪里、哪些部分是稳定的、哪些部分是易变的。然后把这种判断通过提示词传递出去。我举个例子。你做一个小程序的后端需要一个“用户签到”的功能签到规则随时间变化连续签到送积分、节假日双倍积分、新用户首签额外奖励。如果直接让AI写它大概率给你一个巨大的if-else堆在签到Service里。但如果你的模式感知在起作用你会意识到这是典型的策略模式场景。你的提示词会变成“签到规则可能有多种且频繁变化请使用策略模式设计签到奖励计算并将不同规则封装为独立策略类。”实测下来后一种提示词生成的代码维护成本大概是前一种的三分之一。这个差距不是AI模型的差距而是你的架构输入质量的差距。3.3 从“让AI写代码”到“和AIReview代码”设计模式在生成式AI时代还有一个重要用途审查AI生成的代码。很多人把AI当成代码生成器用完就完了。其实AI是可以帮你做代码审查的前提是你得给它设计模式的审查标准。我会把这类提示词存成固定模板每次生成完代码之后跑一遍请以资深架构师的视角审查以下代码重点关注 1. 是否符合单一职责原则这个类是不是承担了过多的职责 2. 是否存在大量if-else或switch-case是否有更合适的策略模式/状态模式可以重构 3. 对象的创建方式是否合理是否有必要引入工厂模式 4. 类之间的耦合是否过高是否可以用依赖倒置来解耦 5. 将来新增需求时代码是否容易扩展哪些地方会成为修改点这段审查提示词的效果我用过不下五十次。它把AI从“写码机器”切换到了“设计评审”的角色。AI会真的指出代码里的问题并且大多数时候给出的重构建议都是靠谱的——因为设计模式本来就是它训练数据里的高频内容。用AI审查AI再用人工做最终决策这个工作流让我在最近两个项目里的代码返工率降低了至少四成。4. 实操实录用生成式AI落地策略模式的全流程4.1 需求描述与模式选型为了把前面讲的东西串起来我完整记录一个最近的实操案例。需求很简单做一个订单模块的运费计算不同运输方式普通快递、顺丰、同城闪送有不同的计费规则而且计费规则将来大概率会调整。这是典型的策略模式场景。但这个需求如果用一句话丢给AI“帮我写一个运费计算的模块”那就废了。我实际的提示词是这样写的项目背景某电商订单系统使用Java 17 Spring Boot 3。 需求实现订单运费计算当前有三种运输方式 1. 普通快递按重量计费首重1kg内10元每超1kg加3元。 2. 顺丰按距离和重量综合计费距离每公里0.5元 重量费用首重15元续重5元/kg。 3. 同城闪送固定距离内一口价20元超出5公里后每公里加2元。 设计约束 - 使用策略模式定义一个FreightStrategy接口每种运输方式一个实现类。 - 提供一个FreightContext上下文类用于根据运输方式代码选择对应的策略。 - 策略对象通过Spring的Autowired注入或手动注册均可。 - 运费计算逻辑不允许耦合在OrderService中OrderService只调用FreightContext的方法。 输出要求给出完整的策略接口、三个策略实现类、FreightContext类、OrderService中的调用示例以及每个类的单元测试。这个提示词里面做了一件很重要的事情把“需求背景、业务规则、设计约束、输出要求”四个维度都给到了。AI不需要猜你要什么,它只需要在你的约束框架内发挥。4.2 AI生成结果与人工修正AI生成的代码总体上不错接口和三个策略类的结构很清晰。但有两个问题需要人工修正第一个问题AI生成的FreightContext类里策略对象是用Map手动注册的。它能跑但没有利用Spring的依赖注入优势。我改成利用Spring容器自动注入所有FreightStrategy实现通过ApplicationContext按bean名称或自定义注解来路由。改完之后新增运输方式只需要加一个实现类连注册代码都不用动。第二个问题AI生成的OrderService调用示例里直接new了一个FreightContext这虽然在demo里能跑但会让OrderService和具体上下文类耦合。我改成把FreightContext作为Spring的Bean注入OrderService。这两个问题完美地说明了前面提到的观点AI能生成结构正确的代码但它不理解你的项目生态和依赖管理方式。最终决定代码质量的那一环还是在人身上。4.3 重构后的关键代码展示修正后的核心代码大概长这样简化版// 策略接口 public interface FreightStrategy { String getTransportType(); BigDecimal calculateFreight(BigDecimal weight, BigDecimal distance); }// 普通快递策略 Component public class StandardExpressFreightStrategy implements FreightStrategy { Override public String getTransportType() { return STANDARD; } Override public BigDecimal calculateFreight(BigDecimal weight, BigDecimal distance) { BigDecimal basePrice new BigDecimal(10); if (weight.compareTo(BigDecimal.ONE) 0) { return basePrice; } BigDecimal extraWeight weight.subtract(BigDecimal.ONE); return basePrice.add(extraWeight.multiply(new BigDecimal(3))); } }// 上下文类负责根据运输方式路由到对应策略 Component public class FreightContext { private final MapString, FreightStrategy strategyMap new HashMap(); public FreightContext(ListFreightStrategy strategies) { strategies.forEach(s - strategyMap.put(s.getTransportType(), s)); } public BigDecimal calculate(String transportType, BigDecimal weight, BigDecimal distance) { FreightStrategy strategy strategyMap.get(transportType); if (strategy null) { throw new IllegalArgumentException(Unsupported transport type: transportType); } return strategy.calculateFreight(weight, distance); } }这段代码看起来简单但它展示了策略模式最核心的价值新增一种运输方式你只需要新增一个实现类不用改FreightContext更不用改OrderService。这就是开闭原则——对扩展开放对修改关闭。4.4 模式落地过程中的三个关键检查点这个案例走完之后我总结了三个每次都要检查的关键点。第一策略的创建方式要给AI讲清楚。是手动注册、Spring注入还是配置文件驱动AI默认会用最简单的方式而最简单的方式往往不够好。这个决策必须在提示词里明确否则生成完后悔改的成本更高。第二策略接口的方法签名要尽量稳定。看上面的calculateFreight(BigDecimal weight, BigDecimal distance)我把两个业务参数直接作为入参。如果将来运费计算需要增加“区域”“是否会员”等新因子这个接口就要改所有实现类都要跟着动。更稳妥的做法是定义一个FreightRequest参数对象把可能变化的因子封装在里面。这个细节AI通常不会主动帮你设计需要你在需求里就考虑好。第三测试要覆盖策略间的隔离性。每个策略类单元测试独立运行不依赖Spring容器只验证计费逻辑的计算正确性。AI生成的测试有时会偷懒只测主流程边界情况比如重量为0、负距离这些你要主动补上。5. 常见问题与排查经验实录AI辅助设计模式避坑指南5.1 AI把代码“模式化”成了过度设计这是我在实际使用中遇到的最频繁的问题。AI对设计模式有一种“用力过猛”的倾向。你让它用策略模式处理运费计算它可能给你搞出五六个接口、三四个工厂类、还有一堆抽象类。代码量翻了三倍可读性反而下降。我排查这类问题的方式很直接检查一个模式是否必要就看它是否真的封住了一个变化点。运费计算方式会变所以策略模式是必要的支付渠道会增多所以工厂模式是必要的。但如果一个HTTP客户端只有一种实现AI硬给它套一层抽象接口和一个工厂那纯属画蛇添足。我的建议是在提示词里加一条硬性约束禁止过度设计不要引入多余的模式或抽象层。每种设计模式的使用都必须是明确的业务变化驱动的。实测这一条提示词能把AI生成的类数量减少五成以上。5.2 AI生成的策略类没有注入Spring容器导致空指针有一次AI生成的策略实现类没有加Component注解结果运行时FreightContext的构造方法拿到一个空的策略列表strategyMap里一个键值对都没有调用运费计算直接NPE。这个问题是AI最常见的低级错误之一——它生成的代码纯逻辑上是通的但忽略了框架的组件扫描机制。排查方法启动日志里看有没有FreightStrategy相关的bean定义信息没有就去检查实现类是不是忘了加注解或者包的扫描路径是否正确。这里有个小技巧把每个策略实现类的类名都设计成[运输方式]FreightStrategy这种格式搜索日志就特别方便。5.3 模式的“语义漂移”问题AI在生成代码时有时候会给模式起误导性的名字。比如一个实际上做“策略选择”的类AI可能叫它FreightUtil一个静态工具类风格的名称。这类问题不报错但代码维护的时候特别坑人。我的做法是在提示词里明确命名规范类名必须体现其模式角色策略接口命名为XxxStrategy实现类命名为XxxStrategyImpl或按业务语义命名 上下文类命名为XxxContext工厂类命名为XxxFactory。命名是代码可读性的第一要素AI在这一点上需要非常强制的约束。5.4 常见问题速查表把我在项目里积累的经验整理成一个速查表方便你在实际使用的时候快速对照。现象可能原因排查/解决思路AI生成代码里类是另一个类的很多倍过度设计检查每个模式是否封住明确的业务变化点删掉凑数的抽象运行时报空的策略列表策略实现类没注册到Spring容器检查Component注解、包扫描路径、策略注册方式功能改了但错误地方的代码被改动AI没有遵循开闭原则提示词加“新增需求时不允许修改既有类只允许新增策略实现”AI生成的UML图与代码不一致设计文档与实现脱节用AI生成设计文档后再生成代码让文档和代码走同一份约束AI使用了一个不熟悉的模式的变体训练数据里的模式版本差异在提示词中给出你期望的结构草图单元测试只测了正常路径AI默认生成happy path测试提示词要求覆盖边界值、异常输入、跨策略对比这个表我一直在用。遇到问题先查表大部分情况都是这几种原因不用每次从零开始分析。5.5 一个压箱底的“模式检索”提示词最后分享一个我存了很久的提示词模板当你拿不准某个需求该用哪种设计模式时直接把它丢给AI我有这样一个需求背景[贴入你的业务背景和功能描述]。 请帮我分析 1. 这个需求中是否存在多个变化点分别是什么 2. 针对每个变化点最适合的设计模式是什么为什么 3. 如果使用这些模式系统的哪些部分会保持稳定哪些部分会变成可扩展点 4. 有没有更简单的替代方案在什么情况下可以不用设计模式 请以对比表的形式输出并给出最终推荐方案。这个提示词的价值在于它把“模式选型”这件事从拍脑袋变成了一种结构化分析。AI的分析不一定100%准确但它能快速给你一个包含多角度考虑的候选列表你再根据自己的项目经验做最终判断。我用这个方式解决过不少原本要开会讨论半天的设计决策。AI的算力用来做头脑风暴效率非常可观。说实话做了这么多年研发我感觉设计模式从来都不是一个“知道”的知识而是一个“持续练习”的敏感度。生成式AI改变了写代码的方式但没有改变软件开发的基本规律——需求会变、系统要维护、代码要被人读。这三条规律恰恰是设计模式存在的全部理由。多花点时间把模式的思想真正内化再借着AI的生成能力落地你的代码质量和开发效率会一起往上涨。后面几篇我会继续拆解不同模式在AI辅助开发中的具体落地姿势也欢迎你带着实际案例来一起讨论。
阅读完成 · 觉得有帮助?