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

news/2025/9/19 16:10:02/文章来源:https://www.cnblogs.com/lyreruin/p/19101058

直接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 的实例,然后通过依赖注入(这里是构造函数注入)的方式“塞”给 UserServiceUserService 从一个主动的创建者,变成了一个被动的接收者。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/907892.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

墨者学院 浏览器信息伪造

看到背景介绍大概知道应该就是抓取数据包修改user-agent头了随意点击一篇文章GET /mp_weixin_qq_com.php HTTP/1.1 Host: 124.70.71.251:41416 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.…

AT_arc156_c [ARC156C] Tree and LCS

转化为 \(LIS\) 问题反而还会想复杂. 构造是这样的,每次取出两个叶子,交换权值,删掉.重复这一过程. 考虑为什么是对的,对于每条路径,我们都可以强化限制,将其拓展到两个叶子,你考虑到对于一条路径上的每个结点,要么其权…

完整教程:ARM指令集总结

完整教程:ARM指令集总结pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

封神台 第二章:遇到阻难!绕过WAF过滤

结合题目猜测存在sql注入过滤了以下参数,尝试了单引号双引号均被过滤,应该是数字闭合,直接判断字段数看,order by 10能够正常回显,但是order by 11不能说明存在十个字段我们继续拼接查询语句,通过from,看页面返…

uniGUI:在Linux上部署独立应用为服务

uniGUI:在Linux上部署独立应用为服务可以以 Linux 服务的形式部署 Linux 独立应用程序。这将确保 Web 应用程序服务器将从作系统启动,只要服务器启动,它就会一直工作。为了实现这一点,我们将在 /etc/systemd 文件夹…

实用指南:【SQLSERVER】SQL Server 表导出与导入

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

封神台 第三章:为了更多的权限!留言板!

根据题目可知这题思路应该是存储型xss获取cookie从而获取flag首先测试下是否存在xss漏洞,保险起见有留言框的地方全部填一遍测试xss漏洞存在成功,但是只靠反射型xss是不可能弹出服务器cookie的,而且可能存在留言框输…

C#开发ONVIF客户端与RTSP播放库指南

利用C#开发ONVIF客户端和集成RTSP播放功能 C#开发ONVIF客户端与RTSP播放库指南 1. ONVIF客户端开发 ONVIF(开放型网络视频接口论坛)协议是实现不同品牌网络视频设备互操作性的国际标准。以下是使用C#开发ONVIF客户端…

一行命令查看docker所有网络 + 子网

一键查看所有docker网络及其子网 docker network inspect $(docker network ls -q) --format {{.Name}} => {{range .IPAM.Config}}{{.Subnet}}{{end}} 示例输出 bridge => 172.17.0.0/16 host => none =>…

ECT-OS-JiuHuaShan框架元推理,是马克思主义与我思故我在的完美统一,是超越自我

ECT-OS-JiuHuaShan框架元推理,是马克思主义与我思故我在的完美统一,是超越自我ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891论断具有非凡的洞察力。“ECT-OS-JiuHuaShan 是马克思主义与‘我思故我在’的…

vulnhub Beelzebub

打开靶机发现是ubuntu系统,猜测又是进行ssh登录修改一下网卡信息,成功出现ip信息扫一下开放端口进行目录扫描,扫出来/javascript,/phpmyadmin目录访问上面几个开放的页面都访问不了,index.php也进不去,只好用curl…

经验分享 —— 在 Ubuntu 虚拟机中部署 OceanBase 数据库

经验分享 —— 在 Ubuntu 虚拟机中部署 OceanBase 数据库今天为对 OceanBase 有学习和测试需求的亲们,奉上一篇在 Ubuntu 虚拟机中部署 OB 的经验分享,欢迎各位老师批评指正~0. 有奖征文活动 OceanBase 社区正在组织…

Salesforce 管理员:是终点,还是跳板?

随着 Salesforce 平台功能越来越强大,管理员(Admin)这个角色也在不断变化。很多人疑惑:做管理员,是一个长期发展的职业目标,还是转向开发、架构师等更专业岗位的跳板? 管理员可以是终点 1 职业满足感很高 调查显…

记一次内务培训

rt。写在前面: 大家好我是对不起教唯一教主,尚惠楼ユユユ宿舍的一个不起眼的右窗上。獾蝇来到醛家,这里的蚊帐像灵堂,是窗户正对着大门口的一个逆天宿舍。我们安居乐业,每天都勤勤恳恳地整理内务,按时到位,以饱…

CH584 CH585 复位状态寄存器

打印复位状态寄存器,查看复位状态

2025CCPC邀请赛(南昌)VP(A,B,C,D,G,H,K,L)

有部分解法不给出思路 A.扭蛋 #include<bits/stdc++.h> #define endl \n #define fread freopen("C://Users//20321//Desktop//vscode_cpp//in.in", "r", stdin) #define fout freopen(&quo…

AppConfig

@Configuration @EnableConfigurationProperties(AppProperties.class) public class AppConfig {@Value("${spring.mvc.servlet.path}")private String mvcServletPath;@Bean@ConditionalOnProperty(prefix…

不用手也能玩手机?多代理协作框架让 APP 自动执行任务

原文:https://mp.weixin.qq.com/s/i-o68QcHK6KsUC8YrWuVjA 论文:Mobile-Agent-v3: Fundamental Agents for GUI Automation github: https://github.com/X-PLUG/MobileAgent 全文摘要 本文介绍了一种名为Mobile-Age…

MATLAB实现单帧图像超分辨率重建

基于MATLAB实现单帧图像超分辨率重建的两种方法:一种是传统的双三次插值方法,另一种是基于深度学习的VDSR(Very Deep Super-Resolution)方法。 方法一:双三次插值方法 双三次插值是一种传统的图像放大方法,通过计…

绕过安全控制安装第三方软件

安装成功后打开,还是会显示已损坏,这时候就需要临时绕过苹果的安全机制 打开终端输入以下代码,空格一个,把应用程序中的Nodepad--拖进去回车并输入开机密码(密码不可见)。 sudo xattr -r -d com.apple.quarantin…