【设计模式】依赖注入和工厂模式

依赖注入与工厂模式教程(Python示例)

概述

本教程将介绍两种重要的设计模式:依赖注入(Dependency Injection) 和工厂模式(Factory Pattern),并通过Python示例展示它们的实际应用。

  1. 依赖注入 (Dependency Injection)

1.1 什么是依赖注入?

依赖注入是一种设计模式,通过外部提供对象所需的依赖关系,而不是在对象内部创建它们。这提高了代码的灵活性、可测试性和可维护性。

1.2 示例:没有使用依赖注入

python 复制代码
class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")

class UserService:
    def __init__(self):
        self.email_service = EmailService()  # 直接创建依赖
    
    def register_user(self, username):
        # 用户注册逻辑
        self.email_service.send_email(f"Welcome {username}!")

# 使用
user_service = UserService()
user_service.register_user("Alice")

1.3 示例:使用依赖注入

python 复制代码
class EmailService:
    def send_email(self, message):
        print(f"Sending email: {message}")

class SMSService:
    def send_sms(self, message):
        print(f"Sending SMS: {message}")

class UserService:
    def __init__(self, notification_service):  # 依赖通过参数注入
        self.notification_service = notification_service
    
    def register_user(self, username):
        # 用户注册逻辑
        self.notification_service.send(f"Welcome {username}!")

# 使用依赖注入
email_service = EmailService()
user_service = UserService(email_service)
user_service.register_user("Alice")

# 可以轻松替换实现
sms_service = SMSService()
user_service_sms = UserService(sms_service)
user_service_sms.register_user("Bob")
  1. 工厂模式 (Factory Pattern)

2.1 什么是工厂模式?

工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,但允许子类决定实例化哪个类。工厂方法让类的实例化推迟到子类。

2.2 简单工厂模式

python 复制代码
class Dog:
    def speak(self):
        return "Woof!"

class Cat:
    def speak(self):
        return "Meow!"

class AnimalFactory:
    @staticmethod
    def create_animal(animal_type):
        if animal_type == "dog":
            return Dog()
        elif animal_type == "cat":
            return Cat()
        else:
            raise ValueError(f"Unknown animal type: {animal_type}")

# 使用工厂
factory = AnimalFactory()
dog = factory.create_animal("dog")
print(dog.speak())  # 输出: Woof!

cat = factory.create_animal("cat")
print(cat.speak())  # 输出: Meow!

2.3 工厂方法模式

python 复制代码
from abc import ABC, abstractmethod

# 抽象产品
class Button(ABC):
    @abstractmethod
    def render(self):
        pass

# 具体产品
class WindowsButton(Button):
    def render(self):
        return "渲染一个Windows风格的按钮"

class WebButton(Button):
    def render(self):
        return "渲染一个Web风格的按钮"

# 抽象创建者
class Dialog(ABC):
    @abstractmethod
    def create_button(self) -> Button:
        pass
    
    def render(self):
        button = self.create_button()
        return button.render()

# 具体创建者
class WindowsDialog(Dialog):
    def create_button(self) -> Button:
        return WindowsButton()

class WebDialog(Dialog):
    def create_button(self) -> Button:
        return WebButton()

# 使用
dialog = WindowsDialog()
print(dialog.render())  # 输出: 渲染一个Windows风格的按钮

dialog = WebDialog()
print(dialog.render())  # 输出: 渲染一个Web风格的按钮
  1. 结合依赖注入和工厂模式

3.1 示例:数据库连接工厂与依赖注入

python 复制代码
from abc import ABC, abstractmethod

# 数据库连接接口
class DatabaseConnection(ABC):
    @abstractmethod
    def connect(self):
        pass
    
    @abstractmethod
    def execute_query(self, query):
        pass

# 具体实现
class MySQLConnection(DatabaseConnection):
    def connect(self):
        return "连接到MySQL数据库"
    
    def execute_query(self, query):
        return f"在MySQL上执行: {query}"

class PostgreSQLConnection(DatabaseConnection):
    def connect(self):
        return "连接到PostgreSQL数据库"
    
    def execute_query(self, query):
        return f"在PostgreSQL上执行: {query}"

# 连接工厂
class DatabaseConnectionFactory:
    @staticmethod
    def create_connection(db_type):
        if db_type == "mysql":
            return MySQLConnection()
        elif db_type == "postgresql":
            return PostgreSQLConnection()
        else:
            raise ValueError(f"不支持的数据库类型: {db_type}")

# 使用依赖注入的服务
class UserService:
    def __init__(self, db_connection: DatabaseConnection):
        self.db_connection = db_connection
        self.db_connection.connect()
    
    def get_user(self, user_id):
        query = f"SELECT * FROM users WHERE id = {user_id}"
        return self.db_connection.execute_query(query)

# 配置和应用
def main():
    # 通过工厂创建依赖
    db_factory = DatabaseConnectionFactory()
    db_connection = db_factory.create_connection("mysql")
    
    # 注入依赖
    user_service = UserService(db_connection)
    result = user_service.get_user(123)
    print(result)

if __name__ == "__main__":
    main()

3.2 更高级的依赖注入容器

python 复制代码
class DIContainer:
    def __init__(self):
        self._services = {}
        self._factories = {}
    
    def register_service(self, name, service):
        self._services[name] = service
    
    def register_factory(self, name, factory):
        self._factories[name] = factory
    
    def get_service(self, name):
        if name in self._services:
            return self._services[name]
        elif name in self._factories:
            return self._factories[name]()
        else:
            raise ValueError(f"未找到服务或工厂: {name}")

# 使用容器
container = DIContainer()
container.register_factory("db_connection", lambda: DatabaseConnectionFactory().create_connection("mysql"))
container.register_service("user_service", UserService(container.get_service("db_connection")))

# 获取服务
user_service = container.get_service("user_service")
result = user_service.get_user(123)
print(result)
  1. 总结

· 依赖注入通过外部提供依赖,提高了代码的灵活性和可测试性

· 工厂模式将对象创建逻辑封装起来,使代码更易于维护和扩展

· 结合使用这两种模式可以创建高度可配置和可测试的应用程序

这两种模式是现代软件开发中的重要概念,特别是在构建大型、可维护的应用程序时。

相关推荐
张较瘦_17 小时前
[论文阅读] 软件工程 - 需求工程 | 2012-2019年移动应用需求工程研究趋势:需求分析成焦点,数据源却藏着大问题?
论文阅读·软件工程·需求分析
沉默媛2 天前
【论文阅读】InnerGS: Internal Scenes Rendering via Factorized 3D Gaussian Splatting
论文阅读·3dgs·内部精细结果重建
czijin2 天前
【论文阅读】Security of Language Models for Code: A Systematic Literature Review
论文阅读·人工智能·安全·语言模型·软件工程
安逸sgr2 天前
Zotero白嫖腾讯云翻译
论文阅读·云计算·腾讯云
飞机火车巴雷特2 天前
【论文阅读】LightThinker: Thinking Step-by-Step Compression (EMNLP 2025)
论文阅读·人工智能·大模型·cot
网安INF2 天前
【论文阅读】-《THE JPEG STILL PICTURE COMPRESSION STANDARD》
论文阅读·计算机视觉
张较瘦_2 天前
[论文阅读] 人工智能 + 软件工程 | ReCode:解决LLM代码修复“贵又慢”!细粒度检索+真实基准让修复准确率飙升
论文阅读·人工智能·软件工程
张较瘦_2 天前
[论文阅读] 软件工程 | 告别“线程安全玄学”:基于JMM的Java类静态分析,CodeQL3分钟扫遍GitHub千仓错误
java·论文阅读·安全
源于花海2 天前
Energy期刊论文学习——基于集成学习模型的多源域迁移学习方法用于小样本实车数据锂离子电池SOC估计
论文阅读·迁移学习·集成学习·电池管理