尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

IOC控制反转的解耦(相比于直接new对象的正向控制)

IOC控制反转的解耦(相比于直接new对象的正向控制)
📅 发布时间:2026/6/19 16:43:06

直接new对象,是你在主动寻找和创建你需要的“零件”;而 IoC 则是你告诉一个“管家”你需要什么“零件”,由“管家”帮你找到或创建好,然后递给你。

这个“管家”就是 IoC 容器(比如 Spring 容器),而“递给你”的这个动作,最常见的实现方式就是依赖注入(Dependency Injection, DI)。

下面我们通过一个例子来解释清楚。

场景:UserService 需要使用 UserDao 来操作数据库

假设我们有一个 UserService 类,它负责用户相关的业务逻辑,比如用户注册。它需要依赖一个 UserDao 类来与数据库进行交互。UserDao 是一个接口,它有一个具体的实现类 UserDaoImpl。

Java

// 数据访问层接口
public interface UserDao {void addUser(User user);
}// 接口的实现类
public class UserDaoImpl implements UserDao {@Overridepublic void addUser(User user) {System.out.println("数据库:添加用户 " + user.getName());}
}

1. 直接 new 一个对象(正向控制)

在这种方式下,UserService 类需要自己负责创建它所依赖的 UserDaoImpl 对象。

代码示例:

Java

public class UserService {// UserService 内部自己创建了 UserDaoImpl 实例private UserDao userDao = new UserDaoImpl();public void register(User user) {// ... 其他业务逻辑,如检查用户名密码等userDao.addUser(user);}
}

分析这种方式的问题(为什么会耦合):

  1. 高度耦合:UserService 和具体的实现类 UserDaoImpl 紧紧地“绑死”在了一起。UserService 的代码里写死了 new UserDaoImpl()。
  2. 难以更换实现:如果有一天,我们不想用 UserDaoImpl 了,想换成一个新的、性能更好的 UserDaoMongoImpl (用 MongoDB 数据库),我们必须修改 UserService 的源代码,把 new UserDaoImpl() 改成 new UserDaoMongoImpl()。如果有一百个类都依赖 UserDaoImpl,你就得改一百次。
  3. 难以测试:当我们要对 UserService 进行单元测试时,我们希望用一个“假的” UserDao (Mock 对象)来模拟数据库操作,而不是真的去连接数据库。但由于 UserDaoImpl 是在 UserService 内部 new 出来的,我们根本没有办法在外部替换它,导致单元测试非常困难。

总结:控制权在 UserService 手中,它主动去创建依赖,导致了它和依赖的实现类之间强烈的耦合关系。

2. 使用 IoC / DI (控制反转)

在 IoC 模式下,UserService 不再自己创建依赖,它只负责“声明”自己需要一个 UserDao 类型的依赖。对象的创建和管理权被交给了 IoC 容器(例如 Spring)。

代码示例:

Java

// 使用 Spring 框架的注解来示意
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service // 告诉 Spring:这个类交给你管理
public class UserService {// 依赖一个接口,而不是具体的实现类private final UserDao userDao;// 通过构造函数注入依赖@Autowiredpublic UserService(UserDao userDao) {this.userDao = userDao;}public void register(User user) {// ... 其他业务逻辑userDao.addUser(user);}
}// UserDaoImpl 也需要被 Spring 管理
@Repository // 告诉 Spring:这个数据访问层类也交给你管理
public class UserDaoImpl implements UserDao {@Overridepublic void addUser(User user) {System.out.println("数据库:添加用户 " + user.getName());}
}

分析这种方式的好处(为什么会解耦):

  1. 实现了解耦:UserService 只依赖于抽象的 UserDao 接口,它根本不知道、也不关心最终传进来的是 UserDaoImpl 还是 UserDaoMongoImpl。它只知道“我需要一个能操作用户的 DAO,是谁不重要,能用就行”。

  2. 轻松更换实现:如果我们想把 UserDaoImpl 换成 UserDaoMongoImpl,我们完全不需要修改 UserService 的代码。只需要在 Spring 的配置中告诉它:“以后凡是需要 UserDao 的地方,都给他 UserDaoMongoImpl 的实例”。

  3. 非常容易测试:在进行单元测试时,我们可以非常轻松地手动创建一个 MockUserDao 对象,然后通过 UserService 的构造函数传进去,从而实现对 UserService 的隔离测试。

    Java

    // 测试代码
    @Test
    void testRegister() {// 创建一个假的 DaoUserDao mockDao = new MockUserDao(); // 手动注入这个假的 Dao 来创建 UserServiceUserService userService = new UserService(mockDao);userService.register(new User("test"));// ... 断言 mockDao 的方法是否被正确调用
    }
    

总结:UserService 失去了创建依赖的控制权,这个控制权被“反转”给了 IoC 容器。容器负责创建好 UserDaoImpl 的实例,然后通过依赖注入(这里是构造函数注入)的方式“塞”给 UserService。UserService 从一个主动的创建者,变成了一个被动的接收者。

相关新闻

  • 墨者学院 浏览器信息伪造
  • AT_arc156_c [ARC156C] Tree and LCS
  • 实用指南:【SQLSERVER】SQL Server 表导出与导入

最新新闻

  • 终极指南:如何使用 nunif iw3 将普通2D视频转换为沉浸式VR 3D体验
  • Display Driver Uninstaller深度清理方案:显卡驱动残留问题的终极解决方案(2024版)
  • 上海正规靠谱空调维修公司推荐,全城优选上海迪迅通制冷设备 - 星际AI
  • SPI协议深度解析:从时钟相位到错误处理,以MC68HC908GR8为例
  • 5分钟掌握2D转3D视频转换:让平面影像立体化的AI魔法
  • 嵌入式系统热设计与功耗分析:从LPC435x数据手册到可靠硬件设计

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号