不遵守依赖倒置原则(dip)会导致业务逻辑与技术细节紧耦合,使系统难以替换、测试和复用;应定义业务意图接口(如communicator、datasink),由业务模块拥有并依赖,具体实现反向适配,通过依赖注入实现无缝替换。

因为一旦这么做了,业务逻辑就和具体技术细节绑死了——串口一换、数据库一迁移、文件路径一调整,核心代码就得跟着改,测试也跑不起来,扩展更无从谈起。
业务层直接调用IO类会带来硬编码耦合
比如写个数据采集服务,直接 new SerialPort() 或 open("data.log", "w"),等于把“怎么通信”“怎么存盘”这些实现细节,一字不差地刻进了业务规则里。这不是在写业务,是在写配置。
- 串口换成TCP或MQTT?得翻出所有业务类,逐行改通信对象
- 日志要从文件切到数据库?得重写所有写入逻辑,还可能牵连异常处理和事务边界
- 单元测试时想模拟失败场景?只能打桩整个IO栈,极易漏测、难隔离
抽象接口才是业务该依赖的“能力契约”
业务真正关心的不是“用串口”,而是“能发指令”;不是“写文件”,而是“能持久化”。把这些意图定义成接口,比如 Communicator、DataSink,业务只和它们交互。
- 接口由业务方定义(例如:send(payload: bytes) → bool),体现真实需求
- 具体实现(SerialPortImpl、PostgreSQLSink)反向实现该接口,服从业务契约
- 谁拥有接口?不是工具库,是业务模块——这是DIP中“接口所有权倒置”的关键
依赖注入让替换变得无声无息
业务类不再自己创建IO对象,而是通过构造函数或方法参数接收已准备好的抽象实例。运行时由外部(如容器、工厂或主程序)决定传哪个具体实现。
- 开发环境传 MockCommunicator,断网也能跑通全部业务逻辑测试
- 生产环境传 TCPCommunicator,切换只需改一行配置,业务代码零修改
- 灰度发布时可同时注入两个实现做对比,业务逻辑完全不受干扰
不遵守DIP,框架和复用就成空谈
高层模块本该是稳定、通用、可跨项目复用的策略层。如果它依赖了某个串口驱动的具体API,那这个模块就永远只能活在那个硬件上。
- 想把同一套报警策略用在工业PLC和IoT边缘设备上?做不到——一个绑RS485,一个绑LoRa
- 想把用户行为分析模块集成进新系统?得先重写所有数据库访问代码
- 框架设计者最怕什么?就是用户说:“你这模块挺好,可惜我用不了——你们依赖了我们不用的SDK”











