✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。
🍎个人主页:Meteors.的博客
💞当前专栏:设计模式
✨特色专栏:知识分享
🥭本文内容:23种设计模式——抽象工厂模式(Abstract Factory Pattern)
📚 ** ps ** :阅读文章如果有问题或者疑惑,欢迎在评论区提问或指出。
目录
一. 背景
对于工厂方法模式,会有一个工厂类里面有一个抽象工厂方法并且返回类型是一个接口基类(大白话讲就是这个方法创建了一个基类的不同实现类,如基类为按钮,我们就可以通过这个方法创建圆形按钮或者方形按钮);
但如果现在有个界面,不仅仅要创建不同类型的按钮,还要创建不同类型的文本框、字体......这种情况怎么办?其实这个时候我们就可以创建一个抽象工厂模式(就是这个界面),里面有多个抽象工厂方法(创建按钮的、创建文本框的、创建字体的......)。抽象工厂。它本质上是多个工厂方法的组合,这些方法共同生产一个产品族。
二. 介绍
抽象工厂模式是一种创建型设计模式,它提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
你可以将其理解为“工厂的工厂”。客户端代码不直接通过
new
来实例化具体的产品,而是通过一个抽象的接口来创建一整组相关的产品。这使得客户端代码与具体的产品类解耦,并且能确保所创建的产品是相互兼容的。
三. 核心角色
- 抽象工厂:声明一个创建一族产品(多个不同产品等级)的接口,包含多个创建产品的方法,如
createButton()
,createTextBox()
。- 具体工厂:实现抽象工厂的接口,负责创建某一族具体的产品。例如,
WindowsFactory
创建 Windows 风格的按钮和文本框,MacFactory
创建 Mac 风格的按钮和文本框。- 抽象产品:声明每种产品类型的接口。例如,
Button
和TextBox
。- 具体产品:实现抽象产品接口,由具体工厂创建。例如,
WindowsButton
,MacButton
,WindowsTextBox
,MacTextBox
。
四. 代码示例
用一个界面为例:
1.抽象产品 & 具体产品
// 抽象产品:按钮 public interface Button { void render(); void onClick(); } // 具体产品:Windows按钮 public class WindowsButton implements Button { @Override public void render() { System.out.println("渲染一个Windows风格的按钮"); } @Override public void onClick() { System.out.println("Windows按钮被点击!"); } } // 具体产品:Mac按钮 public class MacButton implements Button { @Override public void render() { System.out.println("渲染一个Mac风格的按钮"); } @Override public void onClick() { System.out.println("Mac按钮被点击!"); } } // 抽象产品:文本框 public interface TextBox { void render(); } // 具体产品:Windows文本框 public class WindowsTextBox implements TextBox { @Override public void render() { System.out.println("渲染一个Windows风格的文本框"); } } // 具体产品:Mac文本框 public class MacTextBox implements TextBox { @Override public void render() { System.out.println("渲染一个Mac风格的文本框"); } }
2. 抽象工厂 & 具体工厂
// 抽象工厂 public interface GUIFactory { Button createButton(); TextBox createTextBox(); } // 具体工厂:Windows工厂 public class WindowsFactory implements GUIFactory { @Override public Button createButton() { return new WindowsButton(); } @Override public TextBox createTextBox() { return new WindowsTextBox(); } } // 具体工厂:Mac工厂 public class MacFactory implements GUIFactory { @Override public Button createButton() { return new MacButton(); } @Override public TextBox createTextBox() { return new MacTextBox(); } }
3. 客户端代码
客户端代码只依赖抽象工厂和抽象产品,从而与具体平台解耦。
public class Application { private Button button; private TextBox textBox; // 通过构造器注入一个具体的工厂 public Application(GUIFactory factory) { button = factory.createButton(); textBox = factory.createTextBox(); } public void renderUI() { button.render(); textBox.render(); } public static void main(String[] args) { // 根据配置或环境决定使用哪种工厂 GUIFactory factory; String osName = System.getProperty("os.name").toLowerCase(); if (osName.contains("win")) { factory = new WindowsFactory(); } else { factory = new MacFactory(); } Application app = new Application(factory); app.renderUI(); // 输出: // 如果是Windows: // 渲染一个Windows风格的按钮 // 渲染一个Windows风格的文本框 // 如果是Mac: // 渲染一个Mac风格的按钮 // 渲染一个Mac风格的文本框 } }
五. 与简单工厂、工厂方法的区别
特征 简单工厂 工厂方法 抽象工厂 核心思想 由一个工厂类根据传入的参数,静态地决定创建哪一种产品。 定义一个创建对象的接口,但让子类决定实例化哪一个类。 提供一个接口,用于创建相关或依赖对象的家族,而不指定具体类。 工厂角色 一个具体工厂类,包含创建所有产品的逻辑。 一个抽象工厂接口和多个具体工厂实现(每个对应一个产品)。 一个抽象工厂接口和多个具体工厂实现(每个对应一族产品)。 产品维度 一个产品等级(例如:只有按钮)。 一个产品等级(例如:只有按钮)。 多个产品等级(例如:按钮、文本框、复选框等一套产品)。 扩展性 违反开闭原则。要新增产品,必须修改工厂类的逻辑。 符合开闭原则。要新增产品,只需新增一个具体工厂即可。 符合开闭原则。但要新增一个产品族(如Linux主题)很容易,新增一个产品等级(如新增Slider滑块)很困难,需要修改所有工厂接口和类。 复杂度/适用场景 简单,适用于产品类型较少且几乎不会变化的场景。 适中,适用于产品结构单一但需要灵活扩展的场景。 复杂,适用于需要创建一整系列相互关联、相互依赖的产品,并保证它们兼容的场景。 演进关系(从简单到复杂):
- .简单工厂:如果你只有一个产品(比如只有
Button
),用简单工厂就够了。- 工厂方法:当你的产品变得复杂,或者你希望扩展时不修改原有代码(比如未来要加
LinuxButton
),你就为每种按钮建立一个专门的工厂。- 抽象工厂:当你不止有按钮,还有文本框、复选框等一整套需要搭配使用的产品时,工厂方法就不够了。你需要一个能创建整套产品的工厂,这就是抽象工厂。它本质上是多个工厂方法的组合,这些方法共同生产一个产品族。
六. 抽象工厂模式的优缺点
优点:
- 保证了产品的兼容性:确保客户端始终只使用同一产品族中的对象。你不会把一个Windows按钮和一个Mac文本框混在一起用。
- 解耦客户端与具体产品:客户端代码只面向抽象接口编程,使得切换整个产品族变得非常容易(只需换一个具体工厂)。
- 符合开闭原则:易于扩展新的产品族(如新增一个
LinuxFactory
)。缺点:
- 难以支持新的产品种类:这是最大的缺点。如果要为所有工厂增加一个新的产品(如在产品族中增加
Slider
滑块),就需要修改抽象工厂接口GUIFactory
,这会导致所有具体工厂类(WindowsFactory
,MacFactory
)都需要被修改,违反了开闭原则。- 增加了系统的复杂性:类会变得非常多(n个产品族 * m个产品等级 = n*m个类)。
七. 总结与应用场景
抽象工厂模式的核心是创建产品族。
典型应用场景:
- 系统需要独立于其产品的创建、组合和表示时。
- 系统需要配置多个产品族中的某一个时。
- 需要强调一系列相关产品对象的设计以便进行联合使用时。
- 希望提供一个产品类库,但只想暴露它们的接口而不是实现时。
经典例子:
- 跨平台GUI开发(如Java AWT/Swing, QT)。
- 数据库访问层:
Connection
,Command
,DataAdapter
构成一个产品族,可以轻松在SqlServerFactory
和OracleFactory
之间切换。- 游戏开发:为不同风格(科幻、中世纪)的场景创建一套主题资源(建筑、士兵、植被)。
- 日志记录器:创建一套相关的日志组件(记录器、格式化器、附加器)。
最后,
其它设计模式会陆续更新,希望文章对你有所帮助!