一文讲透工厂模式
工厂模式(Factory Pattern)是面向对象编程中一种常见的,用于封装和管理对象的创建过程,将对象的。其核心思想是通过工厂类来代替直接使用new关键字创建对象,从而提高代码的灵活性、可维护性和可扩展性。
·
工厂模式(Factory Pattern)是面向对象编程中一种常见的创建型设计模式,用于封装和管理对象的创建过程,将对象的实例化逻辑与使用逻辑分离。其核心思想是通过工厂类来代替直接使用 new 关键字创建对象,从而提高代码的灵活性、可维护性和可扩展性。
一、工厂模式的核心思想
- 解耦:将对象的创建与使用分离,客户端无需知道具体产品的类名或实现细节。
- 统一管理:通过工厂类集中控制对象的创建逻辑,便于后续扩展或修改。
- 灵活扩展:新增产品时,只需扩展工厂逻辑,而无需修改原有代码(符合开闭原则)。
二、工厂模式的分类
工厂模式通常分为以下三类:
1. 简单工厂模式(Simple Factory Pattern)
- 定义:由一个工厂类根据传入的参数决定创建哪种具体产品对象。
- 特点:
- 工厂类包含一个静态方法(或非静态方法),根据参数返回不同的对象。
- 不属于 GoF 的 23 种经典设计模式,但常作为编程习惯使用。
- 优点:
- 简单直观,代码结构清晰。
- 客户端无需直接依赖具体产品类。
- 缺点:
- 违反开闭原则:新增产品时需修改工厂类的代码。
- 工厂类职责过重,易导致代码臃肿。
- 适用场景:
- 产品种类较少且不频繁变动。
- 对可扩展性要求不高。
示例代码(Java):
// 抽象产品
interface Shape {
void draw();
}
// 具体产品
class Circle implements Shape {
public void draw() {
System.out.println("画一个圆形");
}
}
class Rectangle implements Shape {
public void draw() {
System.out.println("画一个矩形");
}
}
// 简单工厂
class ShapeFactory {
public static Shape createShape(String type) {
if (type.equalsIgnoreCase("circle")) {
return new Circle();
} else if (type.equalsIgnoreCase("rectangle")) {
return new Rectangle();
} else {
throw new IllegalArgumentException("未知图形类型");
}
}
}
// 客户端
public class Client {
public static void main(String[] args) {
Shape shape1 = ShapeFactory.createShape("circle");
shape1.draw(); // 输出:画一个圆形
Shape shape2 = ShapeFactory.createShape("rectangle");
shape2.draw(); // 输出:画一个矩形
}
}
场景举例(go):根据支付方式(如支付宝、微信支付)创建对应的支付处理器对象。
package main
import "fmt"
// 支付接口
type Payment interface {
Pay(amount float64) string
}
// 支付宝支付
type Alipay struct{}
func (a Alipay) Pay(amount float64) string {
return fmt.Sprintf("支付宝支付 %.2f 元", amount)
}
// 微信支付
type WeChatPay struct{}
func (w WeChatPay) Pay(amount float64) string {
return fmt.Sprintf("微信支付 %.2f 元", amount)
}
// 简单工厂
type PaymentFactory struct{}
func (f PaymentFactory) CreatePayment(method string) Payment {
switch method {
case "alipay":
return &Alipay{}
case "wechat":
return &WeChatPay{}
default:
return nil
}
}
func main() {
factory := PaymentFactory{}
// 创建支付宝支付对象
payment1 := factory.CreatePayment("alipay")
if payment1 != nil {
fmt.Println(payment1.Pay(100.0))
}
// 创建微信支付对象
payment2 := factory.CreatePayment("wechat")
if payment2 != nil {
fmt.Println(payment2.Pay(50.0))
}
}
输出结果:
支付宝支付 100.00 元
微信支付 50.00 元
特点:
- 工厂类 PaymentFactory 集中管理对象的创建逻辑。
- 客户端无需直接依赖具体支付类,只需通过工厂创建接口对象。
- 缺点:新增支付方式时需修改工厂类代码(违反开闭原则)。
2. 工厂方法模式(Factory Method Pattern)
- 定义:定义一个创建对象的接口(抽象工厂),由子类决定实例化哪个具体类。
- 特点:
- 将工厂抽象化,每个具体产品对应一个具体工厂。
- 符合开闭原则:新增产品时只需添加新工厂和产品类,无需修改现有代码。
- 优点:
- 解耦更彻底:客户端与具体产品、具体工厂完全解耦。
- 扩展性强:新增产品只需扩展新类。
- 缺点:
- 类数量增加:每增加一个产品,需新增两个类(具体产品类和具体工厂类)。
- 实现复杂度略高。
- 适用场景:
- 需要动态决定创建哪种产品对象。
- 系统需要独立于具体产品的创建逻辑。
示例代码(Java):
// 抽象产品
interface Shape {
void draw();
}
// 具体产品
class Circle implements Shape {
public void draw() {
System.out.println("画一个圆形");
}
}
class Rectangle implements Shape {
public void draw() {
System.out.println("画一个矩形");
}
}
// 抽象工厂
interface ShapeFactory {
Shape createShape();
}
// 具体工厂
class CircleFactory implements ShapeFactory {
public Shape createShape() {
return new Circle();
}
}
class RectangleFactory implements ShapeFactory {
public Shape createShape() {
return new Rectangle();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
ShapeFactory circleFactory = new CircleFactory();
Shape shape1 = circleFactory.createShape();
shape1.draw(); // 输出:画一个圆形
ShapeFactory rectangleFactory = new RectangleFactory();
Shape shape2 = rectangleFactory.createShape();
shape2.draw(); // 输出:画一个矩形
}
}
**场景举例(go):**为每种支付方式定义一个具体工厂,动态决定创建哪种支付对象。
package main
import "fmt"
// 支付接口
type Payment interface {
Pay(amount float64) string
}
// 支付宝支付
type Alipay struct{}
func (a *Alipay) Pay(amount float64) string {
return fmt.Sprintf("支付宝支付 %.2f 元", amount)
}
// 微信支付
type WeChatPay struct{}
func (w *WeChatPay) Pay(amount float64) string {
return fmt.Sprintf("微信支付 %.2f 元", amount)
}
// 支付工厂接口
type PaymentFactory interface {
CreatePayment() Payment
}
// 支付宝工厂
type AlipayFactory struct{}
func (f *AlipayFactory) CreatePayment() Payment {
return &Alipay{}
}
// 微信支付工厂
type WeChatPayFactory struct{}
func (f *WeChatPayFactory) CreatePayment() Payment {
return &WeChatPay{}
}
func main() {
// 使用支付宝工厂创建支付对象
alipayFactory := &AlipayFactory{}
payment1 := alipayFactory.CreatePayment()
fmt.Println(payment1.Pay(200.0))
// 使用微信支付工厂创建支付对象
wechatFactory := &WeChatPayFactory{}
payment2 := wechatFactory.CreatePayment()
fmt.Println(payment2.Pay(150.0))
}
输出结果:
支付宝支付 200.00 元
微信支付 150.00 元
特点:
- 每个支付方式对应一个具体工厂类,符合开闭原则(新增支付方式只需新增工厂和支付类)。
- 客户端与具体支付类完全解耦。
- 缺点:类数量增加,实现复杂度略高。
3. 抽象工厂模式(Abstract Factory Pattern)
- 定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
- 特点:
- 适用于创建一组关联的产品(例如不同品牌的手机、电脑等)。
- 客户端通过抽象接口操作产品族。
- 优点:
- 更强的解耦:客户端与具体产品族完全解耦。
- 支持产品族的切换(例如从苹果系统切换到安卓系统)。
- 缺点:
- 增加新产品族需要修改抽象工厂接口。
- 实现复杂度较高。
- 适用场景:
- 需要创建一组相关或依赖的对象。
- 系统需要独立于产品的具体类。
示例代码(Java):
// 抽象产品A
interface CPU {
void assemble();
}
// 具体产品A1
class IntelCPU implements CPU {
public void assemble() {
System.out.println("组装Intel CPU");
}
}
// 具体产品A2
class AMDCPU implements CPU {
public void assemble() {
System.out.println("组装AMD CPU");
}
}
// 抽象产品B
interface GPU {
void assemble();
}
// 具体产品B1
class NVIDIA_GPU implements GPU {
public void assemble() {
System.out.println("组装NVIDIA GPU");
}
}
// 具体产品B2
class AMDGPU implements GPU {
public void assemble() {
System.out.println("组装AMD GPU");
}
}
// 抽象工厂
interface ComputerFactory {
CPU createCPU();
GPU createGPU();
}
// 具体工厂1(Intel+NVIDIA)
class IntelNVIDIAFactory implements ComputerFactory {
public CPU createCPU() {
return new IntelCPU();
}
public GPU createGPU() {
return new NVIDIA_GPU();
}
}
// 具体工厂2(AMD+AMD)
class AMDFactory implements ComputerFactory {
public CPU createCPU() {
return new AMDCPU();
}
public GPU createGPU() {
return new AMDGPU();
}
}
// 客户端
public class Client {
public static void main(String[] args) {
ComputerFactory factory = new IntelNVIDIAFactory();
CPU cpu = factory.createCPU();
GPU gpu = factory.createGPU();
cpu.assemble(); // 输出:组装Intel CPU
gpu.assemble(); // 输出:组装NVIDIA GPU
}
}
场景举例(GO):创建一组相关的产品族(如不同操作系统的 UI 组件)。
package main
import "fmt"
// 抽象产品:按钮
type Button interface {
Render() string
}
// 抽象产品:文本框
type TextBox interface {
Display() string
}
// 具体产品:Windows 风格按钮
type WindowsButton struct{}
func (b *WindowsButton) Render() string {
return "渲染 Windows 风格按钮"
}
// 具体产品:Windows 风格文本框
type WindowsTextBox struct{}
func (t *WindowsTextBox) Display() string {
return "显示 Windows 风格文本框"
}
// 具体产品:Mac 风格按钮
type MacButton struct{}
func (b *MacButton) Render() string {
return "渲染 Mac 风格按钮"
}
// 具体产品:Mac 风格文本框
type MacTextBox struct{}
func (t *MacTextBox) Display() string {
return "显示 Mac 风格文本框"
}
// 抽象工厂
type GUIFactory interface {
CreateButton() Button
CreateTextBox() TextBox
}
// Windows 工厂
type WindowsFactory struct{}
func (f *WindowsFactory) CreateButton() Button {
return &WindowsButton{}
}
func (f *WindowsFactory) CreateTextBox() TextBox {
return &WindowsTextBox{}
}
// Mac 工厂
type MacFactory struct{}
func (f *MacFactory) CreateButton() Button {
return &MacButton{}
}
func (f *MacFactory) CreateTextBox() TextBox {
return &MacTextBox{}
}
func main() {
// 创建 Windows 风格 UI
platformFactory := &WindowsFactory{}
button := platformFactory.CreateButton()
textBox := platformFactory.CreateTextBox()
fmt.Println(button.Render())
fmt.Println(textBox.Display())
// 创建 Mac 风格 UI
platformFactory = &MacFactory{}
button = platformFactory.CreateButton()
textBox = platformFactory.CreateTextBox()
fmt.Println(button.Render())
fmt.Println(textBox.Display())
}
输出结果:
渲染 Windows 风格按钮
显示 Windows 风格文本框
渲染 Mac 风格按钮
显示 Mac 风格文本框
特点:
- 适用于创建一组相关或依赖的对象(如不同操作系统的 UI 组件)。
- 客户端通过抽象接口操作产品族,屏蔽具体实现细节。
- 缺点:新增产品族时需修改抽象工厂
接口。
三、工厂模式的核心角色
| 角色 | 职责说明 |
|---|---|
| 抽象产品(Product) | 定义产品的公共接口或抽象类,是所有具体产品的父类。 |
| 具体产品(Concrete Product) | 实现抽象产品的具体类,是工厂创建的目标对象。 |
| 抽象工厂(Factory) | 定义创建产品的接口,是工厂方法模式和抽象工厂模式的核心。 |
| 具体工厂(Concrete Factory) | 实现抽象工厂的接口,负责创建具体产品对象。 |
四、工厂模式的应用场景
- 对象创建逻辑复杂:例如需要依赖数据库查询、网络请求或初始化配置。
- 需要统一管理对象的创建:例如日志记录、缓存或资源池的管理。
- 需要动态决定创建哪种对象:例如根据用户输入或环境参数选择不同的实现。
- 需要屏蔽对象的创建细节:例如客户端只需知道接口,无需关心具体实现类。
五、工厂模式的优缺点
5.1 优点
- 解耦:客户端与具体产品类解耦,降低代码耦合度。
- 扩展性:新增产品时无需修改现有代码(符合开闭原则)。
- 集中管理:对象的创建逻辑集中在工厂中,便于统一管理和维护。
- 灵活性:通过工厂可以动态决定创建哪种对象。
5.2 缺点
- 复杂度增加:引入工厂类会增加类的数量,代码结构可能变复杂。
- 过度设计风险:对于简单场景,工厂模式可能显得冗余。
- 静态工厂方法的局限性:简单工厂模式中静态方法无法继承,限制了灵活性。
六、工厂模式的典型应用
- Java 开发:
- Spring 框架:通过
BeanFactory创建 Spring Bean。 - JDBC:通过
DriverManager获取数据库连接。 - JDK 工具类:如
Calendar.getInstance()使用工厂方法。
- Spring 框架:通过
- 开源框架:
- Hibernate:通过
SessionFactory创建 Session 对象。 - Apache Commons:许多工具类(如
DateUtils)使用工厂模式。
- Hibernate:通过
七、总结
7.1 总结对比
| 模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 简单工厂 | 产品种类少且不频繁变动 | 代码简洁,易于理解 | 违反开闭原则,扩展性差 |
| 工厂方法 | 需要动态决定创建哪种产品 | 符合开闭原则,扩展性强 | 类数量增加,实现复杂度略高 |
| 抽象工厂 | 创建一组相关或依赖的对象(产品族) | 更强的解耦,支持产品族切换 | 新增产品族时需修改抽象工厂接口 |
7.2 应用场景建议
- 简单工厂模式:适合简单场景,但不够灵活。
- 工厂方法模式:适合需要动态创建对象的场景,符合开闭原则。
- 抽象工厂模式:适合创建一组相关或依赖的对象,适用于产品族的管理。
通过合理选择工厂模式,可以有效提升代码的灵活性、可维护性和可扩展性,是设计模式中非常实用的一种。
更多推荐

所有评论(0)