工厂模式(Factory Pattern)是面向对象编程中一种常见的创建型设计模式,用于封装和管理对象的创建过程,将对象的实例化逻辑与使用逻辑分离。其核心思想是通过工厂类来代替直接使用 new 关键字创建对象,从而提高代码的灵活性、可维护性和可扩展性。

一、工厂模式的核心思想

  1. 解耦:将对象的创建与使用分离,客户端无需知道具体产品的类名或实现细节。
  2. 统一管理:通过工厂类集中控制对象的创建逻辑,便于后续扩展或修改。
  3. 灵活扩展:新增产品时,只需扩展工厂逻辑,而无需修改原有代码(符合开闭原则)。

二、工厂模式的分类

工厂模式通常分为以下三类:

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) 实现抽象工厂的接口,负责创建具体产品对象。

四、工厂模式的应用场景

  1. 对象创建逻辑复杂:例如需要依赖数据库查询、网络请求或初始化配置。
  2. 需要统一管理对象的创建:例如日志记录、缓存或资源池的管理。
  3. 需要动态决定创建哪种对象:例如根据用户输入或环境参数选择不同的实现。
  4. 需要屏蔽对象的创建细节:例如客户端只需知道接口,无需关心具体实现类。

五、工厂模式的优缺点

5.1 优点
  • 解耦:客户端与具体产品类解耦,降低代码耦合度。
  • 扩展性:新增产品时无需修改现有代码(符合开闭原则)。
  • 集中管理:对象的创建逻辑集中在工厂中,便于统一管理和维护。
  • 灵活性:通过工厂可以动态决定创建哪种对象。
5.2 缺点
  • 复杂度增加:引入工厂类会增加类的数量,代码结构可能变复杂。
  • 过度设计风险:对于简单场景,工厂模式可能显得冗余。
  • 静态工厂方法的局限性:简单工厂模式中静态方法无法继承,限制了灵活性。

六、工厂模式的典型应用

  1. Java 开发
    • Spring 框架:通过 BeanFactory 创建 Spring Bean。
    • JDBC:通过 DriverManager 获取数据库连接。
    • JDK 工具类:如 Calendar.getInstance() 使用工厂方法。
  2. 开源框架
    • Hibernate:通过 SessionFactory 创建 Session 对象。
    • Apache Commons:许多工具类(如 DateUtils)使用工厂模式。

七、总结

7.1 总结对比

模式 适用场景 优点 缺点
简单工厂 产品种类少且不频繁变动 代码简洁,易于理解 违反开闭原则,扩展性差
工厂方法 需要动态决定创建哪种产品 符合开闭原则,扩展性强 类数量增加,实现复杂度略高
抽象工厂 创建一组相关或依赖的对象(产品族) 更强的解耦,支持产品族切换 新增产品族时需修改抽象工厂接口

7.2 应用场景建议

  • 简单工厂模式:适合简单场景,但不够灵活。
  • 工厂方法模式:适合需要动态创建对象的场景,符合开闭原则。
  • 抽象工厂模式:适合创建一组相关或依赖的对象,适用于产品族的管理。

通过合理选择工厂模式,可以有效提升代码的灵活性、可维护性和可扩展性,是设计模式中非常实用的一种。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐