本文是「设计模式实战解读」系列第二篇。系列文章统一按照定义 → 痛点场景 → 模式结构 → 核心实现 → 真实应用 → 常见变种 → 优缺点 → 避坑指南 → FAQ的结构展开每篇聚焦一个模式讲透。一句话定义工厂模式Factory把对象的创建逻辑从使用者中剥离出来由专门的工厂负责创建。调用方只关心我要什么不关心怎么造。归属创建型模式。一、没有工厂时的痛点假设你在做一个消息通知模块需要支持多种发送渠道publicvoidsendNotification(Stringchannel,Stringmessage){if(email.equals(channel)){EmailSendersendernewEmailSender(smtp.xxx.com,465,user,pwd);sender.send(message);}elseif(sms.equals(channel)){SmsSendersendernewSmsSender(https://sms-api.xxx.com,appKey,secret);sender.send(message);}elseif(dingtalk.equals(channel)){DingTalkSendersendernewDingTalkSender(webhook_url,sign_secret);sender.send(message);}elseif(wechat.equals(channel)){WeChatSendersendernewWeChatSender(corpId,agentId,secret);sender.send(message);}}问题违反开闭原则每新增一种渠道都要改这段代码创建逻辑散落各处多处需要创建 Sender重复的构造参数到处写调用方强耦合具体类具体类改了所有调用方都要改无法做单元测试直接 new 出来的对象没法被 mock二、模式结构工厂模式有三个层次层次 1: 简单工厂 Client → Factory.create(type) → ProductA / ProductB / ProductC 层次 2: 工厂方法 Client → AbstractFactory.create() → Product ↑ FactoryA → ProductA ↑ FactoryB → ProductB 层次 3: 抽象工厂 Client → AbstractFactory ├ createProductX() → X1 / X2 └ createProductY() → Y1 / Y2三个层次的适用边界简单工厂产品种类少10新增频率低工厂方法产品种类多经常新增要做到加新品不改旧代码抽象工厂需要创建一组相关联的产品如 UI 组件族按钮输入框下拉框三、核心实现3.1 简单工厂// 产品接口publicinterfaceMessageSender{voidsend(Stringmessage,Stringtarget);}// 具体产品publicclassEmailSenderimplementsMessageSender{/* ... */}publicclassSmsSenderimplementsMessageSender{/* ... */}publicclassDingTalkSenderimplementsMessageSender{/* ... */}// 简单工厂publicclassSenderFactory{privatestaticfinalMapString,SupplierMessageSenderCREATORSnewHashMap();static{CREATORS.put(email,EmailSender::new);CREATORS.put(sms,SmsSender::new);CREATORS.put(dingtalk,DingTalkSender::new);}publicstaticMessageSendercreate(Stringchannel){SupplierMessageSendercreatorCREATORS.get(channel);if(creatornull){thrownewIllegalArgumentException(Unsupported channel: channel);}returncreator.get();}}// 调用方解耦了MessageSendersenderSenderFactory.create(email);sender.send(Hello,testexample.com);用MapString, Supplier代替 if-else新增渠道只需往 Map 里注册不改工厂逻辑。3.2 工厂方法当产品创建逻辑差异大需要不同配置、不同依赖时每种产品对应一个工厂// 抽象工厂publicinterfaceSenderFactory{MessageSendercreate(SenderConfigconfig);}// 具体工厂publicclassEmailSenderFactoryimplementsSenderFactory{OverridepublicMessageSendercreate(SenderConfigconfig){// Email 特有的初始化SMTP 连接、SSL 证书加载SmtpClientsmtpnewSmtpClient(config.getHost(),config.getPort());smtp.auth(config.getUsername(),config.getPassword());returnnewEmailSender(smtp);}}publicclassDingTalkSenderFactoryimplementsSenderFactory{OverridepublicMessageSendercreate(SenderConfigconfig){// 钉钉特有的初始化签名计算、Token 缓存DingTalkClientclientnewDingTalkClient(config.getWebhook());client.setSignSecret(config.getSecret());returnnewDingTalkSender(client);}}调用方通过注入不同工厂来切换产品完全不耦合具体产品类。3.3 结合 Spring 的工厂注册在 Spring 项目中工厂模式最常见的落地方式是策略 自动注册// 每种渠道的 Sender 标注自己的类型Component(email)publicclassEmailSenderimplementsMessageSender{/* ... */}Component(sms)publicclassSmsSenderimplementsMessageSender{/* ... */}Component(dingtalk)publicclassDingTalkSenderimplementsMessageSender{/* ... */}// 工厂利用 Spring 自动收集所有实现ComponentpublicclassSenderFactory{privatefinalMapString,MessageSendersenderMap;// Spring 会自动把所有 MessageSender 按 Bean Name 注入到 MappublicSenderFactory(MapString,MessageSendersenderMap){this.senderMapsenderMap;}publicMessageSendergetSender(Stringchannel){MessageSendersendersenderMap.get(channel);if(sendernull){thrownewIllegalArgumentException(No sender for: channel);}returnsender;}}这是实际项目中用得最多的模式——零手动注册新增一个 Component 就自动生效。四、真实应用场景4.1 框架级应用框架工厂在哪创建什么SpringBeanFactoryBean 实例MyBatisSqlSessionFactorySqlSessionSLF4JLoggerFactoryLoggerJDBCDriverManagerConnectionJacksonObjectMapper (builder)Serializer/DeserializerNettyChannelFactoryChannel4.2 业务场景业务工厂产品为什么用工厂消息通知SenderFactory邮件/短信/钉钉/飞书渠道多、各自初始化逻辑不同支付PaymentFactory微信/支付宝/银联支付方式差异大策略隔离文件解析ParserFactoryExcel/CSV/JSON/XML文件格式各自一套解析逻辑连接器ConnectorFactoryHTTP/RPC/MQ/DB协议不同连接方式差异大报告导出ExporterFactoryPDF/Word/HTML渲染逻辑完全不同规则引擎ConditionFactory等于/包含/大于/正则条件类型多各自求值逻辑独立4.3 iPaaS 连接器场景在 iPaaS 平台中连接器Connector是工厂模式的经典落地用户配置的流程节点 → 指定了 connectorType dingtalk ↓ ConnectorFactory.create(dingtalk) ↓ DingTalkConnector已初始化好 Token 缓存、签名算法连接器的创建涉及 OAuth 初始化、Token 刷新、签名算法加载、SDK 实例化等重逻辑不可能让业务代码直接 new。工厂把这些复杂性封装起来调用方只需factory.create(type)拿到一个可用的连接器实例。五、常见变种5.1 静态工厂方法不新建工厂类在产品类上加静态方法publicclassConnection{privateConnection(Stringurl){/* ... */}// 静态工厂方法命名比 new 更有语义publicstaticConnectionof(Stringurl){returnnewConnection(url);}publicstaticConnectionpooled(Stringurl,intpoolSize){/* ... */}publicstaticConnectionreadonly(Stringurl){/* ... */}}JDK 中大量使用List.of()、Optional.of()、Integer.valueOf()、Collections.emptyList()。优势方法名有语义 可以返回缓存实例 可以返回子类型。5.2 配置驱动工厂产品类型由配置文件/数据库决定工厂在运行时动态加载// 从配置中读取所有渠道 → 类名映射// channel.emailcom.xxx.EmailSender// channel.smscom.xxx.SmsSenderpublicclassDynamicFactory{privatefinalMapString,Class?registrynewHashMap();publicvoidregister(Stringtype,StringclassName)throwsClassNotFoundException{registry.put(type,Class.forName(className));}publicMessageSendercreate(Stringtype)throwsException{return(MessageSender)registry.get(type).getDeclaredConstructor().newInstance();}}这种方式配合 SPIServiceLoader可以做到不改代码、加 jar 包就能新增产品。5.3 延迟创建工厂有些产品创建成本高工厂不立即创建而是返回一个工厂引用publicclassLazyFactory{publicSupplierHeavyObjectcreateLazy(Configconfig){// 不立即创建返回一个 Supplierreturn()-newHeavyObject(config);}}// 使用方在真正需要时才调用 .get()SupplierHeavyObjectlazyfactory.createLazy(config);// ... 很多逻辑 ...HeavyObjectobjlazy.get();// 这时才真正创建六、优缺点优点缺点解耦创建逻辑和使用逻辑增加类的数量每种产品一个类/工厂符合开闭原则新增产品不改工厂简单场景过度使用反而增加复杂度集中管理创建逻辑修改一处生效全局产品需要遵循统一接口有时会过度抽象方便做缓存、池化、日志统计调用方丧失了对象初始化的细粒度控制对单元测试友好可以注入 mock 工厂—七、避坑指南坑 1简单工厂退化成巨型 if-else用MapString, Supplier或 Spring 自动注入代替 if-else。如果仍然用 if-else每次加渠道都改工厂类开闭原则形同虚设。坑 2工厂方法过度使用如果产品只有 2-3 种且不太会增加直接用简单工厂就够了。为 3 种产品建 3 个工厂类 1 个抽象工厂属于过度工程化。坑 3工厂和产品的依赖注入冲突在 Spring 项目中如果产品本身已经被 Spring 管理Component那用MapString, T自动注入比手写工厂更简洁。别自己 new 产品再放进 Map——让 Spring 帮你干。坑 4工厂创建的对象未做生命周期管理工厂创建了对象但没人负责关闭/销毁——连接泄漏、线程泄漏。工厂如果创建有资源的对象连接、流应该同时提供destroy()或配合连接池使用。坑 5产品接口过度抽象为了统一把完全不同的东西强行抽象成一个接口。比如 EmailSender 和 WebhookSender 的参数完全不同邮件有收件人/抄送/附件Webhook 只有 URL非要统一成send(String msg)会导致各种 hack。解法允许产品接口有泛型参数或者把差异部分放到 Config 对象里。八、常见问题FAQQ简单工厂、工厂方法、抽象工厂什么时候用哪个A大部分业务场景简单工厂就够了。只有当满足以下条件时才升级产品种类多10且频繁新增 → 用工厂方法需要创建一组相关联的产品族 → 用抽象工厂。90% 的实际项目只需要简单工厂。Q工厂模式和策略模式有什么区别A工厂模式关注的是创建——如何构造一个对象。策略模式关注的是行为——如何选择一种算法来执行。很多时候二者结合使用工厂创建出策略对象调用方使用策略对象。区别在于侧重点不同。QSpring 的 BeanFactory 是不是工厂模式A是的而且是工厂模式最经典的工业级实现。它不仅创建 Bean还管理 Bean 的生命周期初始化、销毁、作用域singleton/prototype/request、依赖注入、AOP 代理。可以理解为超级工厂。Q什么时候不应该用工厂A对象创建逻辑简单直接 new 就行、没有依赖、产品不需要面向接口编程、不需要 mock 测试——这些场景直接 new 比引入工厂更简洁。不要为了设计模式而设计模式。Q工厂创建的对象应该是单例还是每次 newA取决于产品是否有状态。无状态的服务类如 Sender可以缓存复用有状态的实例如正在使用的 Connection每次创建。通常在工厂内加一层缓存判断即可。九、小结工厂模式的核心价值只有一句话把 “new” 的权利从调用方收回来交给专门的角色管理。记住三个实践要点Spring 项目优先用MapString, T自动注入零代码实现工厂效果简单工厂用 Map Supplier 代替 if-else满足开闭原则工厂创建的对象别忘记生命周期管理——谁创建谁负责销毁下一篇我们聊模板方法模式——当一系列操作有固定的骨架但细节各不相同时如何做到复用骨架、开放细节。标签#设计模式 #工厂模式 #Factory #简单工厂 #工厂方法 #抽象工厂 #Java #Spring #创建型模式 #策略模式 #依赖注入 #面向对象 #软件工程