You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为遵循依赖倒置原则,先实例化依赖再后续更新其值是否合理?

依赖倒置原则(DIP)适配方案合理性分析

场景与初始实现

假设我们有一个Database类,其get_image方法负责返回Image对象。为遵循依赖倒置原则(DIP),设计了一系列接口,初始代码实现如下:

import abc


class ImageInterface(abc.ABC):
    """表示并操作图像"""


class ImageParserInterface(abc.ABC):
    """图像解析器"""

    @abc.abstractmethod
    def decode(self, data: str) -> ImageInterface:
        """将字符串解析为Image对象"""


class DatabaseInterface(abc.ABC):
    """与数据库交互"""

    @abc.abstractmethod
    def get_image(self, image_id: str) -> ImageInterface:
        """根据ID获取数据库中存储的图像"""


class ImageRGB(ImageInterface):
    """表示并操作RGB图像"""


class ImageParserMongoDBToRGB(ImageParserInterface):
    """将MongoDB查询结果转换为ImageRGB对象"""

    def decode(self, data: str) -> ImageInterface:
        """将字符串解析为Image对象"""
        return ImageRGB()


class DatabaseMongoDB(DatabaseInterface):
    """与MongoDB数据库交互"""

    def __init__(self, image_parser: ImageParserInterface):
        self._image_parser = image_parser

    @abc.abstractmethod
    def fetch_image_data(self, image_id: str) -> str:
        ...

    def get_image(self, image_id: str) -> ImageInterface:
        image_data = self.fetch_image_data(image_id)
        return self._image_parser.decode(image_data)

依赖倒置原则(DIP)定义

DIP包含以下核心规则:

  • A1:高层模块不应依赖低层模块的具体实现
  • A2:高层模块与低层模块都应依赖抽象(如接口)
  • B1:抽象不应依赖细节
  • B2:细节(具体实现)应依赖抽象

初始代码的DIP合规性问题

初始实现符合A1和B1:所有接口仅依赖其他接口,没有耦合具体实现。但不符合A2和B2,因为ImageParserMongoDBToRGB直接依赖了具体类ImageRGB,而非抽象的ImageInterface。

修改方案的合理性分析

为满足DIP,有人提出如下修改方案,通过传入空的ImageRGB实例初始化ImageParserMongoDBToRGB:

class ImageParserMongoDBToRGB(ImageParserInterface):
    """将MongoDB查询结果转换为ImageRGB对象"""

    def __init__(self, image: ImageInterface):
        self.image = image

    def decode(self, data: str) -> ImageInterface:
        """将字符串解析为Image对象"""
        self.image.data = data
        return self.image

合理性判断

这种方案部分符合DIP要求,但存在明显设计缺陷:

  1. 符合DIP的部分:ImageParserMongoDBToRGB现在依赖抽象的ImageInterface而非具体的ImageRGB,满足了A2和B2的要求,实现了解耦——后续如果需要替换为其他图像类型(如ImageCMYK),只需传入对应实现类的实例即可,无需修改解析器代码。
  2. 存在的缺陷:
    • 状态复用问题:如果同一个ImageParserMongoDBToRGB实例被多次调用decode方法,会复用同一个image实例,导致前一次解析的图像数据被覆盖,引发状态污染。
    • 违背单一职责:解析器的核心职责应该是创建/解析出图像对象,而非修改外部传入的对象状态。这种设计把对象的创建职责转移到了调用方,增加了调用方的复杂度。

更优的替代方案

如果要严格遵循DIP同时避免上述问题,可以通过依赖注入工厂类的方式实现:

class ImageFactoryInterface(abc.ABC):
    @abc.abstractmethod
    def create_image(self) -> ImageInterface:
        """创建Image实例"""

class ImageRGBFactory(ImageFactoryInterface):
    def create_image(self) -> ImageInterface:
        return ImageRGB()

class ImageParserMongoDBToRGB(ImageParserInterface):
    def __init__(self, image_factory: ImageFactoryInterface):
        self._image_factory = image_factory

    def decode(self, data: str) -> ImageInterface:
        image = self._image_factory.create_image()
        image.data = data
        return image

这种方案中:

  • ImageParserMongoDBToRGB依赖抽象的ImageFactoryInterface,完全满足DIP要求
  • 每次调用decode都会创建新的图像实例,避免状态污染
  • 图像对象的创建职责由工厂类承担,符合单一职责原则

内容的提问来源于stack exchange,提问作者amarion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 06:41:33