PHP控制反转和依赖注入的理解(通俗易懂)

IoC(控制反转)是一种设计思想,它将对象的创建和控制权交给容器,降低了对象间的耦合度。依赖注入(DI)是其实现方式,通过容器动态注入依赖对象,使程序更加灵活和可测试。在PHP框架如laravel中,IoC容器负责对象的生命周期和关系,实现了依赖对象的自动管理和注入。文章通过例子解释了IoC和DI的概念及其在实际开发中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.IoC是什么

2.IoC能做什么

3.IoC和DI

4.IoC(控制反转)

5.DI(依赖注入)

6.我对IoC(控制反转)和DI(依赖注入)的理解


学习PHP各个框架的过程中,都会听过IoC(控制反转) 、DI(依赖注入)这两个概念,总觉得IoC 、DI这两个概念是模糊不清的,是很难理解的,今天跟大家分享网上的一些技术大牛们对IOC的理解以及谈谈我的理解。

1.IoC是什么

Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下: 

  • 谁控制谁,控制什么:
  1. 正常PHP程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
  2. 为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
  • 传统程序设计如下图所示

都是主动去创建相关对象然后再组合起来

  • 当有IoC/DI容器后,程序结构示意如下图所示

当有了IoC/DI的容器后,在客户端类中不再主动去创建这些对象了

2.IoC能做什么

  1. IoC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是 松散耦合,这样也方便测试,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
  2. 其实IoC对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC容器来创建并注入它所需要的资源了。
  3. IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找。

3.IoC和DI

DI—Dependency Injection,即“依赖注入”组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。

  理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”,那我们来深入分析一下

  1. ●谁依赖于谁:当然是应用程序依赖于IoC容器
  2. ●为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源
  3. ●谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象
  4. ●注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)

IoC和DI由什么关系呢?

  1. 其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。

4.IoC(控制反转)

  • 以laravel框架为例:

        首先说说IoC(Inversion of Control,控制反转)对于laravel框架来说,就是由laravel来负责控制对象的生命周期和对象间的关系。

  • 这是什么意思呢?

        举个简单的例子,我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………,想办法认识她们,投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,就必须得到它(自己new一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。

  • 那么IoC是如何做的呢?

        有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。laravel所倡导的开发方式就是如此,所有的类都会在laravel容器中登记,告诉laravel你是个什么东西,你需要什么东西,然后laravel会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 laravel来控制,也就是说控制对象生存周期的不再是引用它的对象,而是laravel。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被laravel控制,所以这叫控制反转。

5.DI(依赖注入)

        IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的

        比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了laravel我们就只需要告诉laravel,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,laravel会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由laravel注入到A中的,依赖注入的名字就这么来的。

  理解了IoC和DI的概念后,一切都将变得简单明了,剩下的工作只是在laravel的框架中堆积木而已。

6.我对IoC(控制反转)和DI(依赖注入)的理解

        在平时的PHP应用开发中,我们要实现某一个功能或者说是完成某个业务逻辑时,至少需要两个或以上的对象来协作完成,在没有使用框架(laravel)的时候,每个对象在需要使用他的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来。

        这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,而这样就会使得对象间的耦合度高了。

        例如:A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起,而使用了框架(laravel)之后就不一样了,创建合作对象B的工作是由(laravel)来做的。

        过程:laravel创建好B对象以后,然后存储到一个容器里面,当A对象需要使用B对象时,laravel就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到框架(laravel)给我们的对象之后,两个人一起协作完成要完成的工作即可。 

  • 所以控制反转IoC(Inversion of Control)是说:

        创建对象的控制权进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,比如转移交给了IoC容器,它就是一个专门用来创建对象的工厂,你要什么对象,它就给你什么对象,有了 IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。 

<think>好的,我现在需要回答用户关于Java中依赖注入的概念及原理的问题。首先,我得理解用户的需求,他们可能对依赖注入不太熟悉,需要简明扼要的解释。根据提供的引用内容,引用[1]提到依赖注入是一种设计模式,使代码更灵活、可维护易扩展。引用[2][3]则进一步联系到Spring的IOC容器,说明其如何实现控制反转依赖注入。 我应该先定义什么是依赖注入,然后解释其原理。需要区分依赖注入控制反转,因为这两个概念常被一起讨论。用户可能对这两者的区别不太清楚,所以需要明确说明:控制反转是更广泛的概念,依赖注入是其实现方式之一。 接下来,要说明依赖注入如何工作,比如容器管理对象的创建依赖关系,而不是由对象自己创建依赖。可以举一个简单的例子,比如一个Service类依赖Repository类,传统方式是Service内部new一个Repository实例,而依赖注入则是通过构造函数或setter方法从外部传入Repository实例。这样代码更解耦,易于测试维护。 然后,结合引用中的内容,特别是引用[3]提到的Spring通过配置定义Bean依赖关系,在容器启动时自动注入。需要提到常见的注入方式,如构造函数注入、setter注入字段注入,并比较它们的优缺点。 可能还需要提到依赖注入的好处,比如减少耦合,提高可测试性,便于管理对象生命周期等。同时,简要说明Spring框架如何实现IOC容器,比如使用XML配置、注解或Java配置类来定义Bean,容器负责实例化注入依赖。 需要确保语言通俗易懂,避免过于技术化的术语,但也要准确。可能用户是初学者,所以例子要简单明了。同时,检查是否有遗漏的关键点,比如依赖注入的三种方式,或者与Service Locator模式的区别?不过根据引用内容,可能不需要深入这些细节,保持回答简洁。 最后,生成相关问题,帮助用户进一步学习,比如原理、不同注入方式的比较,与手动注入的对比,以及Spring中的具体实现。确保问题覆盖用户可能感兴趣的后续知识点。</think>### Java 依赖注入的概念及原理 #### 1. **依赖注入的定义** **依赖注入(Dependency Injection, DI)** 是一种设计模式,用于实现对象之间的解耦。其核心思想是:**将对象的依赖关系(即其他对象或服务)从代码内部创建转移到外部注入**。例如,若类 `A` 需要类 `B` 的功能,传统方式可能直接在 `A` 中实例化 `B`,而依赖注入则通过外部(如容器)将 `B` 的实例传递给 `A`,从而实现松耦合[^1][^3]。 #### 2. **依赖注入的原理** - **控制反转(IoC)**:依赖注入控制反转的一种实现方式。IoC 将对象的创建管理权从开发者转移给容器(如 Spring 框架的 IoC 容器)。开发者只需定义依赖关系,容器负责实例化对象并注入所需的依赖[^2][^3]。 - **实现方式**: 1. **构造函数注入**:通过构造函数参数传递依赖。 ```java public class UserService { private final UserRepository repository; // 依赖通过构造函数注入 public UserService(UserRepository repository) { this.repository = repository; } } ``` 2. **Setter 方法注入**:通过 setter 方法设置依赖。 ```java public class UserService { private UserRepository repository; // 依赖通过 setter 方法注入 public void setRepository(UserRepository repository) { this.repository = repository; } } ``` 3. **字段注入(基于注解)**:使用注解(如 `@Autowired`)直接标注字段。 ```java public class UserService { @Autowired private UserRepository repository; } ``` #### 3. **依赖注入的优势** - **解耦**:对象不直接依赖具体实现,而是依赖接口,便于替换实现类。 - **可测试性**:通过注入模拟对象(Mock),方便单元测试。 - **可维护性**:依赖关系集中管理,修改时无需修改大量代码[^1]。 #### 4. **Spring 框架中的实现** Spring 的 IoC 容器通过以下方式实现依赖注入: - **配置方式**:XML 文件、Java 注解(如 `@Component`、`@Autowired`)或 Java 配置类。 - **容器启动流程**: 1. 扫描配置,识别需要管理的 Bean(如 `UserService` `UserRepository`)。 2. 根据依赖关系(如构造函数参数或注解),自动创建 Bean 并注入依赖。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值