✅ 那什么才算 IoC?我们重申一次标准:
真正的控制反转需要满足这三个条件:
条件 | 是否满足 | 解释 |
---|---|---|
你不创建依赖对象 | ✅ | Kitchen.createFood() or agent.getVehicle() 是“工厂”,你没直接 new |
你不注入依赖对象 | ❌ | 你手动调用 setFood() 或 setVehicle() ,控制权仍在你手中 |
容器/外部框架控制依赖注入流程 | ❌ | 没有任何容器帮你自动注入 |
✅ 所以更准确地说:
示例 | 是否 IoC? | 是否有 IoC 的“倾向/味道”? |
---|---|---|
Kitchen.createFood() + setFood() | ❌ 不是 | ✅ 有工厂感 |
agent.getVehicle() + setVehicle() | ❌ 不是 | ✅ 有 service locator 的风格 |
Spring.getBean(Food.class) 然后自动注入 | ✅ 是 | ✅ 真正的 IoC |
🧠 一句话解释区别:
IoC 是思想(理念),DI 是具体实现方式之一。
🔍 来拆解下这两个词:
✅ IoC(Inversion of Control)控制反转:
- 是一种 设计思想
- 目标是:把控制权从程序员手里“反转”给框架或容器
- 不再由你手动控制程序流程和对象组合,而是由框架来“自动调度”
比如:
你不自己 new,不自己调用 set,框架帮你搞定一切
✅ DI(Dependency Injection)依赖注入:
- 是一种 实现 IoC 的具体技术手段
- 它的核心是:将依赖通过某种方式“注入”给目标对象
- 有 3 种常见形式:
- 构造器注入
- Setter 注入
- 接口注入
✅ 关系总结图:
+--------------------+
| Inversion of |
| Control (IoC) | <== 一种思想、原则
+--------------------+
|
+----------------+------------------+
| |
+-------------+ +--------------------+
| Dependency | | Service Locator |
| Injection | | (另一种实现方式) |
+-------------+ +--------------------+
|
+---------------------------+
| 构造器注入、Setter注入等 |
+---------------------------+
✅ 再简洁一点:
对比项 | IoC | DI |
---|---|---|
是什么 | 一种设计思想 | 一种实现方式 |
控制谁 | 控制“对象如何创建和依赖如何组合”的权力从你手中“反转”出去 | 指定“依赖应该怎么注入进来” |
关系 | 包含关系:DI 是 IoC 的一种实现手段 | 属于 IoC 的一种实践方式 |
举例 | Spring 框架控制 Bean 生命周期 | @Autowired 注入依赖 |
✅ 什么是 Service Locator?
Service Locator 是一种 设计模式,其核心目的是:
提供一个全局的服务查找器,通过它你可以在任何地方查找、获取到需要的服务或依赖对象,而不需要手动创建和管理。
换句话说,它是一个中介,负责管理对象的创建和查找。你只需要请求它来获取服务,而不用关心服务怎么创建或者存在哪儿。
🧠 核心思想:
从服务定位器(Service Locator)中获取服务,而不是自己直接管理和创建对象。
🚨 但是,这种方式的问题:
虽然 Service Locator 提供了“获取依赖”的能力,但它有一个隐含的缺点:
它破坏了“依赖显式化”的原则,也就是,你没有直接看出对象的依赖是什么,导致了代码的可维护性差,特别是当系统变得复杂时。
这和 DI 的区别:
- DI 明确地告诉你:你需要哪些依赖,并且这些依赖会通过某种方式(构造器、setter 等)注入给你。
- Service Locator 则是通过一个全局对象来管理和查找依赖,你在使用时不关心这些依赖怎么被创建的。
✅ 举个简单的例子:
1️⃣ 没有 Service Locator(直接依赖注入):
public class Restaurant {
private final Food food;
public Restaurant(Food food) {
this.food = food;
}
public void order() {
food.eat();
}
}
通过构造器注入 Food
,明确表达了 Restaurant
依赖于 Food
。当你创建 Restaurant
时,需要显式地提供 Food
。
2️⃣ 使用 Service Locator:
public class Restaurant {
private Food food;
public void order() {
// 通过 Service Locator 获取 food
food = ServiceLocator.getService(Food.class);
food.eat();
}
}
在这个例子里,Restaurant
并不直接关心 Food
是怎么被创建的,它只是通过 ServiceLocator.getService(Food.class)
去查询获取 Food
。
你不用显式地提供 Food
,而是让 Service Locator
去处理。
Service Locator 类的简单实现:
public class ServiceLocator {
private static Map<Class<?>, Object> services = new HashMap<>();
// 注册服务
public static <T> void registerService(Class<T> serviceClass, T serviceInstance) {
services.put(serviceClass, serviceInstance);
}
// 获取服务
public static <T> T getService(Class<T> serviceClass) {
return (T) services.get(serviceClass);
}
}
在这段代码中,ServiceLocator
提供了一个静态方法来获取所有注册过的服务对象,而你不需要关心这些对象是怎么创建的。