news 2026/4/17 21:55:28

设计模式学习(5) 23-2 简单工厂、工厂方法 23-4 抽象工厂

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
设计模式学习(5) 23-2 简单工厂、工厂方法 23-4 抽象工厂

0. 个人感悟

  • 工厂模式是经典的创建型模式,工作中也经常用到,值得一学
  • 核心思想是将对象的创建和自身业务隔离开,从而达到复用、解耦的效果
  • 随着业务的逐渐扩展(产品创建逻辑膨胀、不同产品组合工作等),工厂抽象程度不断加深,由简单工厂逐渐演化到工厂方法模式和抽象工厂
  • 每种模式都有自己的优缺点,根据业务进行选择
  • 在实际工作中,可以结合配置文件、spring依赖注入、反射等方式来提高工厂的灵活性和扩展性,在最后展示了自己在工作中实践的一个实例
  • 一个个人学习的经验:认为什么都原汁原味的好,所以学习设计模式开始就直接看原书《设计模式》,然后低估了学习曲线,觉得晦涩难啃,自信受挫,恶性循环。后面改变策略,由易到难,先看一些大家加工过的好懂的,最后在回复本源看母书。认知是不断进步的,不要害怕当前犯错。共勉。

1.简单工厂

1.1概念

定义一个创建对象的类,由这个类来封装创建对象的行为。

在《设计模式:可复用面向对象软件基础》书中将简单工厂模式和工厂方法模式化为一类,认为前者是后者的特例
理解:
定义专门创建对象的类,提高复用,同时将对象的创建和使用进行隔离,降低系统耦合,将创建逻辑封装,提高内聚。

1.2 适配场景(解决什么问题)

  • 多处创建对象,创建对象逻辑相对复杂(封装、复用)
  • 对象有类族划分,比如汽车可以有宝马车、奔驰车等汽车族(管理产品族)
  • 产品族有限,业务变动小,一个类进行管理可以hold住(一个具体工厂管理对象)

1.3实现方法

1.3.1 传统创建方法

  • 哪里需要哪里创建(缺乏复用)
  • 边创建,边使用(缺乏封装,耦合重)
    UML示意:

1.3.2 简单工厂方法:

  • 创建对象的逻辑交给生产工厂,工厂屏蔽实现细节

  • 产品进行类族管理,建立统一的产品接口

  • 客户端与工厂通讯
    UML示意:

  • 抽象产品: 产品的高度抽象,定义产品的行为,一般为接口或者抽象类

  • 具体产品: 抽象产品的实现类,是客户端需要的实例

  • 工厂: 简单工厂的核心,承上启下,承接客户端的创建对象需求,统一管理实例

1.4 代码示例

需求:客户希望我们给做一个淘宝,另一个客户也希望我们做个淘宝,还有一个客户希望我们做个京东。。。
传统的做法是按业务流程来,来一个客户,我们给实现(new)一个具体的购物平台

publicclassTaoBaoShopping{/** * @description 购物 * @author bigHao * @date 2025/12/21 **/publicvoidshopping(){System.out.println("taoBaoShopping");}}
publicclassJDShopping{/** * @description 购物 * @author bigHao * @date 2025/12/21 **/publicvoidshopping(){System.out.println("JDShopping");}}
publicclassClient{staticvoidmain(){JDShoppingjdShopping=newJDShopping();jdShopping.shopping();TaoBaoShoppingtaoBaoShopping=newTaoBaoShopping();taoBaoShopping.shopping();}}

这样做缺乏设计,不利于复用和维护。
我们可以设计一个工厂,由工厂来统一管理对象创建,只需要告诉工厂我们需要什么平台。后续某个平台的代码修改,或者新增平台,只需修改工厂实现。
购物平台类族

publicinterfaceShoppingPlatform{/** * @description 购物 * @author bigHao * @date 2025/12/21 **/voidshopping();}publicclassJDShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("JDShopping");}}publicclassTaoBaoShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("taoBaoShopping");}}

工厂 接受客户端参数,根据参数选择不同的具体产品

publicclassShoppingPlatformFactory{publicstaticfinalStringJD="JD";publicstaticfinalStringTAO_BAO="taoBao";/** * @param shopTye 平台类型 * @return ShoppingPlatform 购物平台 * @description 根据平台类型返回购物平台实现 * @author bigHao * @date 2025/12/21 **/publicShoppingPlatformcreateShoppingPlatform(StringshopTye){returnswitch(shopTye){caseJD->newJDShopping();caseTAO_BAO->newTaoBaoShopping();default->null;};}}

客户端

publicclassClient{staticvoidmain(){StringshopTye="";ShoppingPlatformshoppingPlatform=newShoppingPlatformFactory().createShoppingPlatform(shopTye);}}

1.5 优缺点

结合第一章、第三章记录的1核(高内聚低耦合)4性(复用性 可读性 扩展性 稳定性)7大原则来分析模式的优缺点,这里只列突出的点

  • 优点
    • 高内聚,低耦合: 创建的行为内聚到工厂,客户端不需要和具体产品打交道,只用与工厂通信,降低耦合
    • 单一职责: 创建职责和产品本身业务隔开
    • 开闭原则、扩展性: 符合一定的开闭原则,可以通过增加具体产品和修改工厂代码来达到扩展;抽取抽象产品进行类族管理,后续扩展只用修改工厂代码
  • 缺点
    • 依赖倒置: 依赖具体的工厂类
    • 扩展性: 增加具体产品,需要修改工厂代码,这里的switch需要增加新的case;对象的创建都依赖于工厂,产品类型多时,可能会增加工厂的逻辑(工厂方法模式可以解决这个问题)

2.工厂方法模式

2.1概念

Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation tosubclasses.

翻译:

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

理解:
对比简单工厂统一管理对象创建,工厂方法模式将工厂创建产品的方法抽象化,自身只做接口定义,由具体的实现类来创建产品。因而将“类的实例化延迟到其子类”。

2.2 适配场景

  • 包含简单工厂模式的场景
  • 产品族日益扩大,产品创建逻辑越来越复杂,一个具体工厂逻辑日益膨胀
  • 分工需要。不同的人或团队去维护某个具体产品创建

2.3实现方法

定义里说的很清楚,工厂方法抽象出来,创建具体实例的方法延迟到子工厂

  • 抽象产品: 产品的高度抽象,定义产品的行为,一般为接口或者抽象类
  • 具体产品: 抽象产品的实现类,是客户端需要的实例
  • 抽象工厂: 工厂方法模式的核心。定义创建产品的抽象方法。
  • 具体工厂: 抽象工厂的实现类,创建具体的产品

2.4 代码示例

还是以购物平台为例,改用工厂方法模式
购物平台类族

publicinterfaceShoppingPlatform{/** * @description 购物 * @author bigHao * @date 2025/12/21 **/voidshopping();}publicclassJDShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("JDShopping");}}publicclassTaoBaoShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("taoBaoShopping");}}

抽象工厂和其实现

publicinterfaceIShoppingPlatformFactory{/** * @return ShoppingPlatform 购物平台 * @description 创建购物平台 * @author bigHao * @date 2025/12/21 **/ShoppingPlatformcreateShoppingPlatform();}publicclassJDShoppingFactoryimplementsIShoppingPlatformFactory{@OverridepublicShoppingPlatformcreateShoppingPlatform(){returnnewJDShopping();}}publicclassTaoBaoShoppingFactoryimplementsIShoppingPlatformFactory{@OverridepublicShoppingPlatformcreateShoppingPlatform(){returnnewTaoBaoShopping();}}

客户端

publicclassClient{staticvoidmain(){JDShoppingFactoryjdShoppingFactory=newJDShoppingFactory();jdShoppingFactory.createShoppingPlatform();TaoBaoShoppingFactorytaoBaoShoppingFactory=newTaoBaoShoppingFactory();taoBaoShoppingFactory.createShoppingPlatform();}}

2.5 优缺点

  • 优点
    • 依赖倒置: 工厂进行了抽象,客户端依赖抽象工厂
    • 开闭原则、扩展性: 符合一定的开闭原则,可以通过扩展的方式来增加具体产品和具体工厂
  • 缺点
    • 扩展性: 扩展需要同时增加具体产品和具体工厂; 对比简单工厂,工厂方法模式,其实是将选择具体产品的逻辑从工厂(示例中的switch逻辑)转嫁给了客户端,引入新的产品,势必需要客户端修改代码适配

3.模式名称

3.1概念

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

翻译:

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

理解:
先引入两个概念: 产品族和产品等级结构

  • 产品等级结构: 产品的继承结构,抽象产品和具体产品。比如抽象购物平台类,有淘宝、京东等子类,一起构成了产品等级结构。
  • 产品族:同一个工厂生产的,不同产品等级结构中的一组具体产品。比如京东出品的京东购物和京东外卖,都是属于一个工厂。
购物外卖
京东京东购物京东外卖横向 产品族
淘宝淘宝购物淘宝外卖纵向 产品等级
定义中的“一些列相关或相互依赖”可以理解为不同的抽象产品需要一起工作,而“具体的类”可以理解为具体产品,具体工厂可以理解为一个产品族工厂

3.2 适配场景

  • 包含工厂方法模式场景
  • 一个产品族需要被设计在一起工作

3.3实现方法

定义里也很清楚,抽象工厂中定义创建有依赖关系抽象产品的接口,具体工厂实现创建具体产品族

  • 抽象产品: 产品的高度抽象,定义产品的行为,一般为接口或者抽象类。这里是一个产品族。
  • 具体产品: 抽象产品的实现类,是客户端需要的实例。产品族实例。
  • 抽象工厂: 抽象工厂模式的核心。定义创建一起工作的产品创建的接口方法。
  • 具体工厂: 抽象工厂的实现类,创建具体的产品族。

3.4 代码示例

客户不仅想做购物平台,还想加入外卖到平台中
购物平台类族

publicinterfaceShoppingPlatform{/** * @description 购物 * @author bigHao * @date 2025/12/21 **/voidshopping();}publicclassJDShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("JDShopping");}}publicclassTaoBaoShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("taoBaoShopping");}}

外卖平台类族

publicinterfaceFoodDeliverPlatform{/** * @description 点外卖 * @author bigHao * @date 2025/12/21 **/voiddeliver();}publicclassJDFoodDeliverimplementsFoodDeliverPlatform{@Overridepublicvoiddeliver(){System.out.println("JD food deliver");}}publicclassTaoBaoFoodDeliverimplementsFoodDeliverPlatform{@Overridepublicvoiddeliver(){System.out.println("taoBao food deliver");}}

工厂类族

publicinterfaceIPlatformFactory{/** * @return ShoppingPlatform 购物平台 * @description 创建购物平台 * @author bigHao * @date 2025/12/21 **/ShoppingPlatformcreateShoppingPlatform();/** * @return FoodDeliverPlatform 外卖平台 * @description 创建外卖平台 * @author bigHao * @date 2025/12/21 **/FoodDeliverPlatformcreateFoodDeliverPlatform();}publicclassJDFactoryimplementsIPlatformFactory{@OverridepublicShoppingPlatformcreateShoppingPlatform(){returnnewJDShopping();}@OverridepublicFoodDeliverPlatformcreateFoodDeliverPlatform(){returnnewJDFoodDeliver();}}publicclassTaoBaoFactoryimplementsIPlatformFactory{@OverridepublicShoppingPlatformcreateShoppingPlatform(){returnnewTaoBaoShopping();}@OverridepublicFoodDeliverPlatformcreateFoodDeliverPlatform(){returnnewTaoBaoFoodDeliver();}}

客户端

publicclassClient{staticvoidmain(){JDFactoryjdFactory=newJDFactory();jdFactory.createShoppingPlatform();jdFactory.createFoodDeliverPlatform();TaoBaoFactorytaoBaoFactory=newTaoBaoFactory();taoBaoFactory.createShoppingPlatform();taoBaoFactory.createFoodDeliverPlatform();}}

3.5 优缺点

  • 优点
    • 扩展性: 易于产品族的更换
  • 缺点
    • 扩展性: 扩展一个产品等级结构,需要在增加新的产品族的同时去更改抽象工厂和具体工厂,当然这个是设计灵活性需要付出的代价,实际项目需要均衡考虑;客户端需要指定具体工厂,当然这个其实可以通过读取配置文件等方式来进行优化。后面会举一个之前在项目中使用过的简单工厂+配置文件配置来实现不用修改客户端代码

4.简单工厂+配置文件+依赖注入实践

背景:
三种工厂模式中各有优缺点。其中有一个比较共性的缺点:当需要更改实现时,还是需要更改代码,比如简单工厂需要更改自身swich代码来更换选择实例,工厂方法和抽象工厂需要客户端来选择用哪个工厂。在工作中使用简单工厂时也遇到了这个问题,最后先到了一套方案,大家可以参考。
解决思路:有没有好的办法来解决呢。归纳起来有3个重要步骤,可以针对来解决

  • 变更的传递。如何将告诉程序我要更改实现。传统实现是改客户端代码,选择其它实现。 这点可以通过加载配置文件来替代。
  • 如何纳管所有的实现。 拿到变更的参数了,那么需要和系统中所有实例进行匹配,首先需要纳管所有实现。简单工厂其实没有纳管功能,需要自己去依赖具体产品。 Spring的出现替我们解决了这个问题。
  • 传递和匹配。 有了变更参数和所有实现,接下来指定匹配规则,这个可以提前约定,比如在抽象产品中添加一个抽象方法,返回一个产品标识。用这个标识与输入匹配。
    代码demo示例:
    产品类族: 注意加入注解,让容器纳管
@ComponentpublicinterfaceShoppingPlatform{/** * @description 购物 * @author bigHao * @date 2025/12/22 **/voidshopping();}@ComponentpublicclassJDShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("JDShopping");}}@ComponentpublicclassTaoBaoShoppingimplementsShoppingPlatform{@Overridepublicvoidshopping(){System.out.println("taoBaoShopping");}}

工厂: 注入所有实现,提供匹配参数-实例的方法

@ComponentpublicclassShoppingPlatformFactory{// 这里会注入ShoppingPlatform的所有实现@ResourceprivateList<ShoppingPlatform>shoppingPlatforms;/** * @param shopTye 平台类型 * @return ShoppingPlatform 购物平台 * @description 根据平台类型返回购物平台实现 * @author bigHao * @date 2025/12/22 **/publicOptional<ShoppingPlatform>createShoppingPlatform(StringshopTye){// 这里的匹配逻辑是类名.startsWith入参 比如JDShopping可以匹配上JD TaoBaoShopping可以匹配上TaoBaoreturnshoppingPlatforms.stream().filter(item->item.getClass().getSimpleName().startsWith(shopTye)).findFirst();}}

配置文件

platform.type=JD

客户端: 这里让程序在项目初始化后启动

@ComponentpublicclassStartedEventListenerimplementsApplicationListener<ApplicationStartedEvent>{@Value("${platform.type}")privateStringplatformType;@ResourceprivateShoppingPlatformFactoryshoppingPlatformFactory;@OverridepublicvoidonApplicationEvent(ApplicationStartedEventevent){System.out.println("应用启动完成,通知监听器执行其它操作--start");System.out.println("platformType : "+platformType);Optional<ShoppingPlatform>shoppingPlatform=shoppingPlatformFactory.createShoppingPlatform(platformType);booleanisPresent=shoppingPlatform.isPresent();if(isPresent){System.out.println("instance outPut: ");shoppingPlatform.get().shopping();}else{System.out.println("get instance failed.");}System.out.println("应用启动完成,通知监听器执行其它操作--end");}}

输出:

应用启动完成,通知监听器执行其它操作--start platformType:JD instance outPut:JDShopping应用启动完成,通知监听器执行其它操作--end

参考:

  • 韩顺平 Java设计模式
  • 张维鹏 Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)
  • alpha_panda 设计模式之工厂模式(factory pattern)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 10:56:27

LangFlow中的二维码生成器:快速创建可扫描内容

LangFlow中的二维码生成器&#xff1a;快速创建可扫描内容 在智能系统日益渗透日常场景的今天&#xff0c;如何让大语言模型&#xff08;LLM&#xff09;的输出不再局限于对话框里的文字&#xff0c;而是真正“走出去”&#xff0c;与物理世界产生互动&#xff1f;一个简单的二…

作者头像 李华
网站建设 2026/3/31 10:36:23

面向初学者的树莓派烧录实验指导书:零基础适用

零基础也能搞定树莓派烧录&#xff1a;从一张空卡到系统启动的完整实战指南 你是不是也曾在看到别人用树莓派做机器人、搭建家庭服务器或DIY智能音箱时心生羡慕&#xff1f;但一想到“烧录系统”“刷镜像”这些术语就望而却步&#xff1f; 别担心&#xff0c;今天我们就来 彻…

作者头像 李华
网站建设 2026/4/17 7:15:50

树莓派拼音输入法安装:面向学生的通俗解释

让树莓派“说”中文&#xff1a;学生也能轻松搞定拼音输入法 你有没有这样的经历&#xff1f;在树莓派上写Python代码时&#xff0c;想加一句中文注释&#xff1a;“这里计算圆的面积”&#xff0c;结果发现键盘敲出来的全是英文字母——系统根本不认识“pingyin”&#xff1f;…

作者头像 李华
网站建设 2026/4/14 8:19:46

LangFlow与冥想引导结合:心理健康辅助工具

LangFlow与冥想引导结合&#xff1a;心理健康辅助工具 在焦虑成为常态、注意力日益稀缺的今天&#xff0c;越来越多的人开始寻求正念冥想作为情绪调节的出口。从Apple Watch上的呼吸提醒&#xff0c;到Calm和Headspace这类应用的流行&#xff0c;数字化冥想正在悄然改变人们的心…

作者头像 李华
网站建设 2026/4/17 1:31:22

WeChatExtension-ForMac:打造专业级Mac微信增强体验

WeChatExtension-ForMac&#xff1a;打造专业级Mac微信增强体验 【免费下载链接】WeChatExtension-ForMac Mac微信功能拓展/微信插件/微信小助手(A plugin for Mac WeChat) 项目地址: https://gitcode.com/gh_mirrors/we/WeChatExtension-ForMac 还在为Mac微信功能限制而…

作者头像 李华
网站建设 2026/4/17 2:51:25

LangFlow与用户行为分析结合:洞察AI应用使用模式

LangFlow与用户行为分析结合&#xff1a;洞察AI应用使用模式 在人工智能技术快速渗透各行各业的今天&#xff0c;大语言模型&#xff08;LLM&#xff09;已不再是实验室里的概念玩具&#xff0c;而是真正落地于客服系统、内容生成、智能助手等实际场景中的生产力工具。然而&…

作者头像 李华