在后端系统中,经常会出现多个不同的Controller模块,调用同一个Service的情况。那这个时候,如果重新new不同的Service对象,是不合适的,因为我们希望确保它们使用的是同一个Service实例,也就是维持单例模式。
在大型应用中,手动管理这种依赖关系,会变得非常复杂和繁琐。所以,IoC(Inverse of Control,控制反转)就提供了这么一种解决方案。
IoC容器在应用初始化时,会查找每个类上声明的依赖,并按照顺序创建相应的实例,并且管理这些实例,当需要使用某个依赖时,IoC容器会帮你提供相应的对象实例。
由于一般情况下,都是根据类的依赖关系来进行容器的实例创建的,所以,也会更具这种实现方式称之为依赖注入(Dependency Injection, DI),通过依赖注入,外部容器将所需的依赖对象注入到目标对象中,而不是由目标对象自己创建依赖对象
IoC 提供了一种结构上的思想:将控制权从程序的对象转移到外部容器或框架中。
DI 是 IoC 的具体实现之一,它通过外部注入依赖的方式将对象所依赖的组件或服务交给容器进行管理。
传统方式
class PaymentService {
processPayment(amount) {
console.log(`处理付款金额: $${amount}`);
return true; // 假设支付成功
}
}
class ShippingService {
shipOrder(orderDetails) {
console.log(`订单发货至: ${orderDetails.address}`);
}
}
class OrderService {
constructor() {
// 直接在构造函数中创建依赖
this.paymentService = new PaymentService(); // 直接创建 PaymentService 实例
this.shippingService = new ShippingService(); // 直接创建 ShippingService 实例
}
createOrder(amount, address) {
console.log(`创建订单金额: $${amount}`);
// 调用 paymentService 进行支付
const paymentSuccess = this.paymentService.processPayment(amount);
if (paymentSuccess) {
console.log(`订单创建成功!`);
// 调用 shippingService 发货
this.shippingService.shipOrder({ address });
} else {
console.log(`付款失败。订单创建已中止!`);
}
}
}
// 直接创建 OrderService 的实例,而不是从容器获取
const orderService = new OrderService();
// 创建订单
orderService.createOrder(200, '成都市天府三街');
IoC方式
class Container {
constructor() {
this.services = new Map(); // 存储服务实例
}
// 注册服务到容器中
register(name, service) {
this.services.set(name, service);
}
// 获取服务实例
get(name) {
const service = this.services.get(name);
if (!service) {
throw new Error(`Service ${name} not found!`);
}
// 如果服务是一个工厂函数,执行它来创建实例
if (typeof service === 'function') {
const instance = service(this); // 创建实例
this.services.set(name, instance); // 缓存实例
return instance;
}
return service;
}
}
// PaymentService 负责处理支付
class PaymentService {
processPayment(amount) {
console.log(`处理付款金额: $${amount}`);
return true; // 假设支付成功
}
}
class ShippingService {
shipOrder(orderDetails) {
console.log(`订单发货至: ${orderDetails.address}`);
}
}
// OrderService 依赖 PaymentService和ShippingService,创建订单时需要调用支付和发货服务
class OrderService {
constructor(paymentService, shippingService) {
this.paymentService = paymentService;
this.shippingService = shippingService;
}
createOrder(amount, address) {
console.log(`创建订单金额:$${amount}`);
const paymentSuccess = this.paymentService.processPayment(amount);
if (paymentSuccess) {
console.log(`订单创建成功!`);
this.shippingService.shipOrder({ address });
} else {
console.log(`付款失败。订单创建已中止!`);
}
}
}
// 创建一个 IoC 容器实例
const container = new Container();
container.register('paymentService', new PaymentService()); // 直接注册 PaymentService
container.register('shippingService', new ShippingService()); // 直接注册 ShippingService
container.register('orderService', (container) => {
return new OrderService(
container.get('paymentService'),
container.get('shippingService')
); // 注入 PaymentService 和 ShippingService
});
// 从容器中获取 OrderService,并创建一个订单
const orderService = container.get('orderService');
orderService.createOrder(200, '成都市天府三街');
最终实现的效果其实是一致的,但是我们仔细看一下,如果传统的方式,再次来获取订单服务,我们可能会不经意之间直接又会重新new一次订单服务,但是,IoC的模式下,我们是从容器中直接获取的,从而保证了订单服务始终都是同一个对象。




