控制反转(Inversion of Control)这个名字是什么意思?到底是谁的“控制权”被“反转”了?从前是谁控制?现在又是谁控制?

我们来一步步拆解这个问题。

到底是谁的“控制权”被“反转”了?

简单回答:是创建和管理对象的控制权被反转了。

再详细一点:是应用程序代码(我们自己写的业务代码)对“依赖对象”的创建、查找和注入的控制权,“反转”或者说“交给了一个外部的容器(比如 Spring IoC 容器)


从前是谁控制?(没有 IoC 的情况)

在没有 IoC 的世界里,我们自己的代码掌握着绝对的控制权。

让我们回到上一篇文章中那个 UserService 的例子:

public class UserService {
    // 我(UserService)需要一个 UserRepository。
    // 所以,我(UserService)自己来决定用哪个,并且自己来创建它!
    // 这就是“正向控制”或者说“传统控制”。
    private UserRepository userRepository = new MySqlUserRepository(); 

    public void doSomething() {
        // ...
    }
}

在这个场景下,控制链条是这样的:

  1. 谁是主控方?
    UserService

  2. 它控制了什么?

    • 创建时机:当 new UserService() 被执行时,new MySqlUserRepository() 也立刻被执行。UserService 决定了 MySqlUserRepository 的出生时间。
    • 具体实现UserService 在代码里写死了 MySqlUserRepository,它直接控制了依赖的具体类型。如果想换,必须改 UserService 的代码。
    • 生命周期userRepository 实例的生命周期与 UserService 实例紧密绑定。UserService 实例被销毁时,userRepository 实例也会被回收。

总结一下:在传统模式下,一个对象如果需要依赖另一个对象,它必须亲自负责创建(或获取)这个依赖。这种主动、直接的控制方式,我们称之为“正向控制流”。


现在又是谁控制?(使用 IoC 的情况)

在使用了 IoC 之后,控制权从我们的业务代码,转移到了一个专门的“IoC 容器”手上

我们再看 IoC 版本的代码:

@Service
public class UserService {
    // 我(UserService)只是声明:我需要一个 UserRepository。
    // 至于这个 UserRepository 是谁,从哪来,什么时候创建,我不管!
    // 我等着别人(IoC容器)把它送过来。
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void doSomething() {
        // ...
    }
}

在这个场景下,控制链条发生了“反转”

  1. 谁是主控方?
    Spring IoC 容器

  2. 它控制了什么?

    • 创建时机:容器在启动时,会扫描并创建所有被管理的 Bean(比如 MySqlUserRepository 的实例)。它不再是由 UserService 来决定。
    • 具体实现:容器根据配置(比如哪个类上标了 @Repository 注解)来决定实例化哪一个 UserRepository 的实现。UserService 完全不知道也不关心具体是 MySqlUserRepository 还是 MongoUserRepository
    • 依赖注入:容器创建完 UserService 后,发现它需要一个 UserRepository,于是容器主动将自己管理的 UserRepository 实例,“注入”(送)给 UserServiceUserService 从“主动索取”变成了“被动接收”。

总结:在 IoC 模式下,对象不再自己创建依赖,而是被动地等待容器将依赖注入进来。原来的主动方(UserService)变成了被动方,而容器则成为了新的主动方。这个主客关系的颠倒,就是“控制反转”这个名字的精髓。

比喻:“好莱坞原则”

IoC 的思想有一个非常著名的别称,叫做**“好莱坞原则”(The Hollywood Principle)**。

这句话是:“Don’t call us, we’ll call you.”(别来找我们,我们会来找你。)

  • 没有 IoC(你自己找工作):你(UserService)主动去给各个电影公司(new MySqlUserRepository(), new OracleUserRepository())打电话,询问是否有工作机会。你控制着整个过程。
  • 使用 IoC(你签约了经纪人):你(UserService)签约了一个顶级经纪人(Spring IoC 容器)。你只需要告诉经纪人:“我是一个演员,我需要角色(UserRepository)”。然后你就回家等着。当有合适的角色时,经纪人会主动打电话给你,把剧本(依赖实例)给你。

在这个比喻里:

  • 你(演员) 就是我们的业务组件,比如 UserService
  • 经纪人 就是 IoC 容器。
  • 打电话这个动作的“控制权”,从你手上,反转到了经纪人手上。

这就是“控制反转”的全部意义:将组件之间复杂的创建和依赖关系,从组件内部代码中剥离出来,交由一个中立的第三方容器去统一管理,从而实现解耦和更高的灵活性。

### 什么是控制反转Inversion of Control, IoC)? 控制反转是一种软件设计原则,其核心思想是将程序的控制流从传统的由开发者主动控制的方式,转变为由外部框架或容器来主导控制的方式。在传统的程序设计中,一个类通常会直接创建和管理它所依赖的对象,这种方式称为“正转”。而在控制反转的模式下,类不再负责主动创建依赖对象,而是由外部容器来负责创建和注入这些依赖,这种控制权的转移被称为“反转”[^1]。 ### 控制反转的作用 控制反转的主要作用在于解耦和提高代码的可维护性与可扩展性。通过将依赖对象的创建和管理交给容器,类不再需要关心具体的依赖实现,而是通过接口进行交互,从而实现了依赖倒置原则。这种设计方式使得系统更容易扩展和测试,因为模块之间的依赖关系更加松散,且可以动态替换[^3]。 ### 控制反转的实现方式 控制反转通常通过依赖注入(Dependency Injection, DI)来实现。依赖注入是一种设计模式,它通过构造器注入、设值注入等方式将依赖对象传递给类,而不是由类自己创建依赖对象。例如,在Spring框架中,可以通过构造器注入依赖对象,从而实现控制反转[^4]。 ```java class Car { private Engine engine; public Car(Engine engine) { this.engine = engine; } public void startCar() { engine.start(); } } ``` 在上述代码中,`Car` 类不再直接创建具体的 `Engine` 实现,而是通过构造器接收一个 `Engine` 接口的实例。这种方式使得 `Car` 类可以与具体的 `Engine` 实现解耦,而具体的 `Engine` 实现则由外部容器注入[^4]。 ### 控制反转的具体应用场景 控制反转广泛应用于现代软件开发框架中,例如Spring框架。在Spring中,控制反转通过IoC容器实现,容器负责管理对象的生命周期和依赖关系。开发者只需声明对象的依赖关系,而不需要关心这些依赖对象是如何创建和管理的。这种设计方式不仅提高了代码的灵活性,还简化了测试和维护过程[^4]。 ### 控制反转的其他方面 除了依赖注入,控制反转还可以体现在程序的其他方面,例如线程管理和方法调用。在传统的独立应用程序中,主方法通常负责调用第三方库的功能,而在控制反转的模式下,第三方库会将控制权交还给开发者,从而使得程序的控制流发生变化[^2]。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值