设计模式 - 工厂模式 笔记

一、简单工厂模式

驱动力 : 将复杂对象的创建、初始化逻辑,从业务代码中抽离出来,交给一个专门的工厂类全权负责。

案例:(图像、视频、按钮 三元素)

假设你在做一个平面编辑器,里面有三种元素:图像元素、视频元素、按钮元素。它们都继承自同一个基类"图形元素",而图形元素有一个尺寸属性。

当前项目的需求是这样的:图像元素创建后,默认尺寸得是 512×512;视频元素默认 1920×1080;按钮元素默认 160×90。

问题来了。如果你在代码各处直接 new,那么每创建一个元素,后面都得跟着一串尺寸赋值。这不仅麻烦,还埋下了隐患------万一哪天需求变了,比如图像元素的默认尺寸要改成 1080×1080,你就得满项目去找所有 new 图像元素 的地方,一个一个改。

而且,这不光是尺寸的事。将来还可能给元素加默认名字、默认位置等等初始化参数。每一次改动,都是一场"全局搜索"的噩梦。

为什么不直接改构造函数?

有小伙伴会想:那把默认参数直接写进构造函数里不就行了?其实也可以,但这会让数据对象变得过于定制化,难以复用。

这个项目要的默认参数,换一个项目可能完全不需要。如果把项目特有的初始化逻辑硬塞进构造函数里,这个类就被"绑死"在当前项目中了。下次想复用,还得再改回来。构造函数应该保持纯粹,只做对象本身必要的基础初始化。

引入简单工厂:

更好的做法是引入一个工厂,让它来专门负责创建这些元素。业务层只需要告诉工厂"我要一个图像元素"(比如传一个字符串或枚举),工厂就负责把对象 new 出来、把该设的默认尺寸、默认名字一并处理好,最后把一个"开箱即用"的成品对象返回。

这样一来,职责就清晰了:

· 数据对象层:只定义对象本身,不掺和项目特有的初始化。

· 工厂层:封装了当前项目所需要的创建逻辑和默认配置。

· 业务层:只负责拿对象来用,完全不关心对象是怎么造出来的。

这样改了需求,也只需要改工厂里的那一处创建逻辑,影响范围被牢牢控制住了。


二、工厂方法模式

驱动力: 简单工厂虽然好,但所有元素的创建逻辑都堆在一个工厂类里。当元素种类变多,或者每种元素的创建过程本身就非常复杂时,这个工厂类会变得臃肿不堪。工厂方法模式的核心思路是:把"创建"这件事本身也抽象出去,让每个具体元素都拥有自己专属的工厂,业务层只和抽象的工厂接口打交道。

还是那个平面编辑器的例子:

在简单工厂里,我们有一个工厂,业务层传个"图像元素"的字符串进去,它返回一个初始化好的对象。这在小规模下完全没问题。

但现在项目变大了,需求也更复杂了。图像元素的创建步骤多了起来:除了设尺寸,还得加载默认占位图、校验图片格式、设置初始图层顺序等等。视频元素也类似:要设尺寸、要加载首帧缩略图、要检查编码格式。按钮元素则有自己的一套配置:设尺寸、设默认文案、绑定默认点击事件。更麻烦的是,这些逻辑还在随着迭代不断变化。

如果这些都还挤在一个工厂类里,这个类会迅速膨胀成"超级工厂"。每加一种新元素,或者改一下创建逻辑,都要动这个类。它变成了整个系统的修改热点,违背了开闭原则------我们对修改不开放,对扩展才开放。

解决方案:让每种元素拥有自己的专属工厂。

我们把创建行为抽象成一个工厂接口 ,比如叫 元素工厂,里面只定义一个方法:创建元素()

然后,为每一种元素都写一个具体的工厂类:

  • 图像元素工厂:实现 创建元素(),在里面 new 出图像元素,把尺寸设成 512×512,加载默认占位图,做完那一套它独有的初始化逻辑。

  • 视频元素工厂:实现 创建元素(),同样负责视频元素那套专属的创建和初始化。

  • 按钮元素工厂:实现 创建元素(),负责按钮元素的定制化初始化。

业务层怎么用呢?

业务层不再直接跟哪个具体的工厂类打交道。它只需要依赖那个抽象的 元素工厂 接口。当它需要一个图像元素时,外部注入一个 图像元素工厂 的实例进来,业务层只调用 工厂.创建元素(),拿到成品对象,完全不关心这个对象是怎么造出来的。

好处在哪里?

  • 符合开闭原则 :哪天产品说要新增一种"音频元素",你不需要去修改任何已有的工厂代码。只需要新建一个 音频元素工厂 类,实现 元素工厂 接口,把音频元素的创建逻辑放进去就行了。对扩展开放,对修改关闭。

  • 职责更单一:每个具体工厂只负责一种对象的创建。逻辑集中,好维护,好测试。

  • 更灵活地替换:业务层依赖的是接口。你可以在不同的场景下,注入不同的工厂实现。比如在测试时注入一个"测试用图像元素工厂",它创建的是不加载占位图的轻量对象,一切都在掌控之中。

一句话总结:

  • 简单工厂:一个工厂包揽所有产品的创建,适合产品种类少、创建逻辑简单的场景。

  • 工厂方法:把工厂也抽象出来,每种产品对应一个专属工厂,让系统的创建行为更容易扩展,而不是一直在老代码上修修补补。


三、抽象工厂模式

驱动力: 工厂方法解决了一种对象的创建问题,但现实中的对象往往是成族、成套出现的。比如平面编辑器里,不会只有"图像元素"这一种对象------你还有配套的 "工具栏"、"属性面板"。当你需要创建一整套互相配合的对象时,就得保证它们属于同一套对象,不能乱套。抽象工厂的核心就是:提供一个接口,用来创建一系列相关或相互依赖的对象,而不需要指定它们具体的类。

案例:(换一套主题)

经过工厂方法的改造,我们的编辑器已经很清晰了:每种元素有自己的专属工厂,扩展新元素很方便。

但需求又升级了。产品经理说,我们的编辑器要做多皮肤主题:一个浅色主题,一个深色主题。这意味着什么?

  • 如果用户选的是浅色主题,那么创建出来的图像元素应该是浅色风格的样子,配套的工具栏是浅色底色的,属性面板也是浅色的。

  • 如果用户选的是深色主题,所有这些东西都应该是深色风格。

问题来了。如果只是用工厂方法,你就得分别调用 图像元素工厂 创建图像、工具栏工厂 创建工具栏、属性面板工厂 创建属性面板。万一哪天某个调用方不小心混搭了------用深色工厂创建了图像元素,却用浅色工厂创建了工具栏------整个界面就风格割裂了。

我们需要一个更高层级的工厂,来保证"成套创建"的一致性。

这就是抽象工厂的舞台。

解决方案:把工厂也分家族。

我们定义一个抽象工厂接口 ,叫 UI工厂,里面不只有一个方法,而是一组方法:

  • 创建图像元素()

  • 创建工具栏()

  • 创建属性面板()

然后,为每个主题创建一套具体工厂:

  • 浅色UI工厂:实现 UI工厂 接口。它内部创建的所有东西都是浅色风格------创建图像元素() 返回一个浅色默认的图像元素,创建工具栏() 返回浅色背景的工具栏,创建属性面板() 返回浅色面板。

  • 深色UI工厂:同样实现 UI工厂 接口。它内部创建的所有东西都是深色风格。

业务层怎么用呢?

业务层只需要依赖那个抽象的 UI工厂 接口。用户选了什么主题,系统就给它注入对应的具体工厂(浅色UI工厂深色UI工厂)。业务层只管调用 ui工厂.创建图像元素()ui工厂.创建工具栏(),拿到的就是一套风格统一的对象,绝无混搭的可能。

更进一步:产品族变了怎么办?

假设哪天产品经理说,我们要新增一个"夜间主题"。你只需要做两件事:

  1. 新建一个 夜间UI工厂 类,实现 UI工厂 接口,在里面把图像元素、工具栏、属性面板都做成夜间风格。

  2. 在主题选择的地方,加上"夜间主题→夜间UI工厂"的映射。

你没有动任何已有的工厂代码,也没有动业务层的逻辑。这就是抽象工厂的强大之处:它不仅能创建单个对象,还能保证产品族的一致性,并且对扩展开放、对修改关闭。

和工厂方法的关系:

抽象工厂内部,通常就是用工厂方法来实现的。浅色UI工厂 里的 创建图像元素(),本质上就是一个工厂方法。所以抽象工厂常常是一组工厂方法的集合,这些方法负责创建属于同一个"家族"的不同"产品"。

一句话总结:

  • 简单工厂:一个工厂创建多种产品,封装了初始化细节。

  • 工厂方法:每种产品配一个专属工厂,让创建行为容易扩展。

  • 抽象工厂:提供一个工厂家族,保证创建出来的多个产品是配套的、风格统一的。

抽象工厂模式,为什么以【抽象】为开头:

强调这个工厂是抽象的 ------而不是一个具体的工厂类,它定义了一个抽象的规则 ,用来约束那一群具体的工厂 ,让他们必须生产出风格统一的产品族

在编程里有一条金科玉律:(要依赖于抽象,不要依赖于具体。)

这就像你开一家咖啡馆,你签合同时签的是**"牛奶供应商"**(抽象),而不是具体的"蒙牛"或"伊利"(具体)。 这样当你发现蒙牛涨价时,你可以瞬间换成伊利,而你的咖啡机(业务逻辑)不需要改动任何接口,因为它只认"牛奶"这个抽象概念。

相关推荐
一只机电自动化菜鸟4 小时前
一建机电备考笔记(36) 焊接技术—焊接方法与工艺(含考频+题型)
笔记·学习·职场和发展·生活·学习方法
小袁说公考4 小时前
公考培训机构2025年度测评:财务健康度与用户体验重构排名格局
大数据·人工智能·经验分享·笔记·其他·重构·ux
许长安4 小时前
gRPC Keepalive 机制
c++·经验分享·笔记·rpc
RainCity5 小时前
Java Swing 自定义组件库分享(五)
java·笔记·后端
脆皮炸鸡7555 小时前
库制作与原理~静态库&静态链接
linux·经验分享·笔记·学习方法
书生的梦5 小时前
《神经网络与深度学习》学习笔记(一)
笔记·深度学习·神经网络
袁小皮皮不皮5 小时前
HCIP-BFD 学习笔记
运维·服务器·网络·笔记·网络协议·学习·智能路由器
智者知已应修善业5 小时前
51单片机4按键控制共阳LED霓虹灯切换1整体闪烁2流水下3流水上4间隔闪烁】2023-10-27
c++·经验分享·笔记·算法·51单片机