pin_drop当前位置:知识文库 ❯ 图文

Python工厂模式完全指南 - 三种工厂实现详解

一、什么是工厂模式

工厂模式(Factory Pattern)是创建型设计模式中最常用的模式之一。它的核心思想是:将对象的创建过程封装起来,调用者无需知道具体的创建细节,只需要通过工厂获取所需对象即可。

工厂模式分为三种主要类型:简单工厂模式、工厂方法模式和抽象工厂模式。这三种模式的复杂度递增,适用的场景也有所不同。

工厂模式的核心优势

  • 解耦合:客户端代码与具体类解耦,只依赖抽象接口

  • 可扩展:新增产品类型时,只需添加新的工厂类,符合开闭原则

  • 集中管理:对象创建逻辑集中在一处,便于维护和修改

  • 延迟实例化:可以动态决定创建哪个具体类


二、简单工厂模式

简单工厂模式是最基础的工厂模式,通过一个工厂类根据参数创建不同的产品对象。

1. 基础实现

代码示例

from abc import ABC, abstractmethod

# 产品基类
class Payment(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

# 具体产品
class Alipay(Payment):
    def pay(self, amount):
        print(f"支付宝支付: {amount}元")

class WechatPay(Payment):
    def pay(self, amount):
        print(f"微信支付: {amount}元")

class BankPay(Payment):
    def pay(self, amount):
        print(f"银行卡支付: {amount}元")

# 简单工厂
class PaymentFactory:
    @staticmethod
    def create_payment(method):
        payment_map = {
            "alipay": Alipay,
            "wechat": WechatPay,
            "bank": BankPay
        }
        if method not in payment_map:
            raise ValueError(f"不支持的支付方式: {method}")
        return payment_map[method]()

# 使用工厂
factory = PaymentFactory()
payment = factory.create_payment("alipay")
payment.pay(100)  # 支付宝支付: 100元

payment2 = factory.create_payment("wechat")
payment2.pay(200)  # 微信支付: 200元

2. 使用字典映射的优化实现

代码示例

class PaymentFactory:
    """使用注册机制的简单工厂"""
    _payments = {}
    
    @classmethod
    def register(cls, name):
        def decorator(payment_cls):
            cls._payments[name] = payment_cls
            return payment_cls
        return decorator
    
    @classmethod
    def create(cls, method, **kwargs):
        if method not in cls._payments:
            raise ValueError(f"不支持的支付方式: {method}")
        return cls._payments[method](**kwargs)

# 注册支付方式
@PaymentFactory.register("alipay")
class Alipay:
    def pay(self, amount):
        print(f"支付宝支付: {amount}元")

@PaymentFactory.register("wechat")
class WechatPay:
    def pay(self, amount):
        print(f"微信支付: {amount}元")

# 使用
payment = PaymentFactory.create("alipay")
payment.pay(50)
特性 简单工厂 工厂方法 抽象工厂
复杂度
产品类型 单一产品族 单一产品族 多个产品族
开闭原则 不遵守(需修改工厂) 遵守 遵守
适用场景 产品少、变化小 产品易扩展 产品族关联

三、工厂方法模式

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化哪个类。它将实例化延迟到子类中,符合开闭原则。

1. 基础实现

代码示例

from abc import ABC, abstractmethod

# 产品基类
class Document(ABC):
    @abstractmethod
    def open(self):
        pass
    
    @abstractmethod
    def save(self):
        pass

# 具体产品
class WordDocument(Document):
    def open(self):
        print("打开Word文档")
    
    def save(self):
        print("保存为.docx格式")

class PDFDocument(Document):
    def open(self):
        print("打开PDF文档")
    
    def save(self):
        print("保存为.pdf格式")

class ExcelDocument(Document):
    def open(self):
        print("打开Excel文档")
    
    def save(self):
        print("保存为.xlsx格式")

# 工厂基类
class DocumentFactory(ABC):
    @abstractmethod
    def create_document(self) -> Document:
        pass

# 具体工厂
class WordFactory(DocumentFactory):
    def create_document(self) -> Document:
        return WordDocument()

class PDFFactory(DocumentFactory):
    def create_document(self) -> Document:
        return PDFDocument()

class ExcelFactory(DocumentFactory):
    def create_document(self) -> Document:
        return ExcelDocument()

# 使用
def process_document(factory: DocumentFactory):
    doc = factory.create_document()
    doc.open()
    doc.save()

process_document(WordFactory())
process_document(PDFFactory())

2. 使用注册表模式的工厂方法

代码示例

class DocumentRegistry:
    """文档工厂注册表"""
    _factories = {}
    
    @classmethod
    def register(cls, doc_type):
        def decorator(factory_cls):
            cls._factories[doc_type] = factory_cls
            return factory_cls
        return decorator
    
    @classmethod
    def create(cls, doc_type):
        if doc_type not in cls._factories:
            raise ValueError(f"不支持的文档类型: {doc_type}")
        return cls._factories[doc_type]().create_document()

# 注册工厂
@DocumentRegistry.register("word")
class WordFactory:
    def create_document(self):
        return WordDocument()

@DocumentRegistry.register("pdf")
class PDFFactory:
    def create_document(self):
        return PDFDocument()

# 使用
doc = DocumentRegistry.create("word")
doc.open()
doc.save()

四、抽象工厂模式

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它适用于创建产品族的场景。

1. UI组件工厂示例

代码示例

from abc import ABC, abstractmethod

# 产品族A - 按钮
class Button(ABC):
    @abstractmethod
    def render(self):
        pass

class WindowsButton(Button):
    def render(self):
        print("渲染Windows风格按钮")

class MacButton(Button):
    def render(self):
        print("渲染Mac风格按钮")

class LinuxButton(Button):
    def render(self):
        print("渲染Linux风格按钮")

# 产品族B - 输入框
class InputBox(ABC):
    @abstractmethod
    def render(self):
        pass

class WindowsInputBox(InputBox):
    def render(self):
        print("渲染Windows风格输入框")

class MacInputBox(InputBox):
    def render(self):
        print("渲染Mac风格输入框")

class LinuxInputBox(InputBox):
    def render(self):
        print("渲染Linux风格输入框")

# 产品族C - 对话框
class Dialog(ABC):
    @abstractmethod
    def show(self):
        pass

class WindowsDialog(Dialog):
    def show(self):
        print("显示Windows风格对话框")

class MacDialog(Dialog):
    def show(self):
        print("显示Mac风格对话框")

class LinuxDialog(Dialog):
    def show(self):
        print("显示Linux风格对话框")

# 抽象工厂
class UIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button:
        pass
    
    @abstractmethod
    def create_input_box(self) -> InputBox:
        pass
    
    @abstractmethod
    def create_dialog(self) -> Dialog:
        pass

# 具体工厂
class WindowsUIFactory(UIFactory):
    def create_button(self) -> Button:
        return WindowsButton()
    
    def create_input_box(self) -> InputBox:
        return WindowsInputBox()
    
    def create_dialog(self) -> Dialog:
        return WindowsDialog()

class MacUIFactory(UIFactory):
    def create_button(self) -> Button:
        return MacButton()
    
    def create_input_box(self) -> InputBox:
        return MacInputBox()
    
    def create_dialog(self) -> Dialog:
        return MacDialog()

class LinuxUIFactory(UIFactory):
    def create_button(self) -> Button:
        return LinuxButton()
    
    def create_input_box(self) -> InputBox:
        return LinuxInputBox()
    
    def create_dialog(self) -> Dialog:
        return LinuxDialog()

# 使用工厂
def create_ui(factory: UIFactory):
    button = factory.create_button()
    input_box = factory.create_input_box()
    dialog = factory.create_dialog()
    
    button.render()
    input_box.render()
    dialog.show()

# 创建Windows风格UI
print("=== Windows UI ===")
create_ui(WindowsUIFactory())

# 创建Mac风格UI
print("\n=== Mac UI ===")
create_ui(MacUIFactory())

2. 数据库连接抽象工厂

代码示例

from abc import ABC, abstractmethod

# 数据库连接产品族
class Connection(ABC):
    @abstractmethod
    def connect(self):
        pass

class Query(ABC):
    @abstractmethod
    def execute(self, sql):
        pass

class Transaction(ABC):
    @abstractmethod
    def begin(self):
        pass
    
    @abstractmethod
    def commit(self):
        pass

# MySQL产品族
class MySQLConnection(Connection):
    def connect(self):
        print("连接到MySQL数据库")
        return self

class MySQLQuery(Query):
    def execute(self, sql):
        print(f"执行MySQL查询: {sql}")

class MySQLTransaction(Transaction):
    def begin(self):
        print("开始MySQL事务")
    def commit(self):
        print("提交MySQL事务")

# PostgreSQL产品族
class PostgreSQLConnection(Connection):
    def connect(self):
        print("连接到PostgreSQL数据库")
        return self

class PostgreSQLQuery(Query):
    def execute(self, sql):
        print(f"执行PostgreSQL查询: {sql}")

class PostgreSQLTransaction(Transaction):
    def begin(self):
        print("开始PostgreSQL事务")
    def commit(self):
        print("提交PostgreSQL事务")

# 抽象工厂
class DatabaseFactory(ABC):
    @abstractmethod
    def create_connection(self) -> Connection:
        pass
    
    @abstractmethod
    def create_query(self) -> Query:
        pass
    
    @abstractmethod
    def create_transaction(self) -> Transaction:
        pass

# 具体工厂
class MySQLFactory(DatabaseFactory):
    def create_connection(self):
        return MySQLConnection()
    def create_query(self):
        return MySQLQuery()
    def create_transaction(self):
        return MySQLTransaction()

class PostgreSQLFactory(DatabaseFactory):
    def create_connection(self):
        return PostgreSQLConnection()
    def create_query(self):
        return PostgreSQLQuery()
    def create_transaction(self):
        return PostgreSQLTransaction()

# 使用
def init_database(factory: DatabaseFactory):
    conn = factory.create_connection()
    conn.connect()
    query = factory.create_query()
    query.execute("SELECT * FROM users")
    tx = factory.create_transaction()
    tx.begin()
    tx.commit()

init_database(MySQLFactory())

五、Python中的工厂模式最佳实践

Python的动态特性让工厂模式的实现更加灵活。以下是一些Python特有的最佳实践。

1. 使用函数作为工厂

代码示例

# Python中函数本身就是一等公民,可以直接作为工厂
def create_animal(animal_type, **kwargs):
    """使用函数实现工厂模式"""
    animals = {
        "dog": lambda: Dog(**kwargs),
        "cat": lambda: Cat(**kwargs),
        "bird": lambda: Bird(**kwargs),
    }
    if animal_type not in animals:
        raise ValueError(f"未知动物类型: {animal_type}")
    return animals[animal_type]()

class Dog:
    def __init__(self, name="旺财"):
        self.name = name
    def speak(self):
        return f"{self.name}: 汪汪!"

class Cat:
    def __init__(self, name="咪咪"):
        self.name = name
    def speak(self):
        return f"{self.name}: 喵喵!"

class Bird:
    def __init__(self, name="小鸟"):
        self.name = name
    def speak(self):
        return f"{self.name}: 啾啾!"

# 使用
dog = create_animal("dog", name="大黄")
print(dog.speak())  # 大黄: 汪汪!

2. 使用类方法作为工厂

代码示例

from datetime import datetime, date

class DateUtil:
    """使用类方法实现工厂方法模式"""
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    
    @classmethod
    def from_string(cls, date_str):
        """从字符串创建日期"""
        parts = date_str.split("-")
        return cls(int(parts[0]), int(parts[1]), int(parts[2]))
    
    @classmethod
    def from_timestamp(cls, timestamp):
        """从时间戳创建日期"""
        dt = datetime.fromtimestamp(timestamp)
        return cls(dt.year, dt.month, dt.day)
    
    @classmethod
    def today(cls):
        """创建今天的日期"""
        t = datetime.now()
        return cls(t.year, t.month, t.day)
    
    def __str__(self):
        return f"{self.year}-{self.month:02d}-{self.day:02d}"

# 使用不同的工厂方法
d1 = DateUtil.from_string("2026-06-12")
d2 = DateUtil.from_timestamp(1718179200)
d3 = DateUtil.today()

print(f"字符串创建: {d1}")
print(f"时间戳创建: {d2}")
print(f"今天: {d3}")

提示:Python的datetime模块本身就大量使用了类方法工厂模式,如datetime.fromtimestamp()datetime.strptime()等,这是非常值得学习的实践。


六、实际应用场景

1. 数据解析器工厂

代码示例

import json
import csv
import io

class DataParser(ABC):
    """数据解析器基类"""
    @abstractmethod
    def parse(self, data):
        pass
    
    @abstractmethod
    def serialize(self, obj):
        pass

class JSONParser(DataParser):
    def parse(self, data):
        return json.loads(data)
    
    def serialize(self, obj):
        return json.dumps(obj, ensure_ascii=False, indent=2)

class CSVParser(DataParser):
    def parse(self, data):
        reader = csv.DictReader(io.StringIO(data))
        return list(reader)
    
    def serialize(self, obj):
        if not obj:
            return ""
        output = io.StringIO()
        writer = csv.DictWriter(output, fieldnames=obj[0].keys())
        writer.writeheader()
        writer.writerows(obj)
        return output.getvalue()

class XMLParser(DataParser):
    def parse(self, data):
        # 简化的XML解析
        print("解析XML数据")
        return {}
    
    def serialize(self, obj):
        print("序列化为XML")
        return "<root></root>"

# 解析器工厂
class ParserFactory:
    """文件格式解析器工厂"""
    _parsers = {
        "json": JSONParser,
        "csv": CSVParser,
        "xml": XMLParser
    }
    
    @classmethod
    def get_parser(cls, file_format):
        parser_cls = cls._parsers.get(file_format.lower())
        if not parser_cls:
            raise ValueError(f"不支持的文件格式: {file_format}")
        return parser_cls()

# 使用
parser = ParserFactory.get_parser("json")
data = '{"name": "Python", "version": "3.12"}'
result = parser.parse(data)
print(f"解析结果: {result}")

csv_parser = ParserFactory.get_parser("csv")
csv_data = "name,age\nPython,30\nJava,28"
result = csv_parser.parse(csv_data)
print(f"CSV解析: {result}")

2. 通知服务工厂

代码示例

class Notification:
    """通知基类"""
    def send(self, recipient, message):
        raise NotImplementedError

class EmailNotification(Notification):
    def send(self, recipient, message):
        print(f"[邮件] 发送至 {recipient}: {message}")

class SMSNotification(Notification):
    def send(self, recipient, message):
        print(f"[短信] 发送至 {recipient}: {message}")

class PushNotification(Notification):
    def send(self, recipient, message):
        print(f"[推送] 发送至 {recipient}: {message}")

class WechatNotification(Notification):
    def send(self, recipient, message):
        print(f"[微信] 发送至 {recipient}: {message}")

class NotificationFactory:
    """通知服务工厂"""
    
    @staticmethod
    def create_notification(notification_type):
        factories = {
            "email": EmailNotification,
            "sms": SMSNotification,
            "push": PushNotification,
            "wechat": WechatNotification
        }
        
        cls = factories.get(notification_type)
        if not cls:
            raise ValueError(f"不支持的通知类型: {notification_type}")
        return cls()

# 使用
def send_alert(user, message, channels):
    """向用户发送多渠道通知"""
    for channel in channels:
        notification = NotificationFactory.create_notification(channel)
        notification.send(user["phone"], message)

# 发送通知
user = {"name": "张三", "phone": "13800138000"}
send_alert(user, "服务器CPU使用率超过90%!", ["email", "sms", "wechat"])

小贴士

在实际项目中,可以结合依赖注入框架(如 dependency-injector)来管理工厂,让对象的创建和注入更加灵活和可测试。


七、小结与练习题

核心要点总结

  • 简单工厂:一个工厂类通过条件判断创建不同产品,适合产品少的场景

  • 工厂方法:将创建逻辑延迟到子类,每个产品对应一个工厂,符合开闭原则

  • 抽象工厂:创建产品族的工厂,适用于多个相关产品的场景

  • Python特色:利用函数、类方法、装饰器和注册表,工厂模式实现更加灵活

练习题

练习1

请使用工厂方法模式实现一个图形渲染器,支持渲染不同格式的图片(PNG、JPEG、GIF、SVG),并使用注册表模式让新格式可以轻松扩展。

练习2

设计一个外卖平台的订单工厂,支持创建不同类型的订单(普通订单、预约订单、团购订单、拼单订单),每种订单有不同的处理流程和计费规则。在实际场景中应用工厂模式。

常见问题

工厂模式和依赖注入有什么区别?

工厂模式关注对象的创建过程,依赖注入关注对象之间的依赖关系管理。工厂可以是依赖注入的一种实现方式。在实际项目中,两者经常结合使用:通过依赖注入容器管理工厂,再由工厂创建具体对象。

Python中需要抽象基类才能实现工厂模式吗?

不需要。Python的鸭子类型特性意味着只要对象有相同的方法就可以互换使用。但使用ABC(抽象基类)可以提供更好的代码可读性和IDE支持,在大型项目中推荐使用。

简单工厂违反了开闭原则吗?

是的。简单工厂在添加新产品时需要修改工厂类的条件判断代码。如果需要严格遵守开闭原则,应该使用工厂方法模式或注册表模式,这样新增产品时只需添加新类,不需要修改已有代码。

工厂模式会影响性能吗?

工厂模式本身只会增加一层函数调用,性能影响可以忽略不计。但如果工厂中使用了大量的字典查找、反射或动态导入,在性能极度敏感的场景下需要注意优化。一般情况下,工厂模式带来的可维护性收益远大于微小的性能损失。

标签: Python 工厂模式 设计模式 抽象工厂 开闭原则 面向接口编程

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python单例模式完全指南 - 线程安全实现与实战应用 下一篇: Python观察者模式完全指南 - 发布订阅与事件驱动

poll相关推荐