Skip to content

控制反转

控制反转

控制反转(Inversion of Control, IoC) 是一种软件设计原则,它通过将对象的控制权从类自身转移到外部容器或框架中,从而减少了类与类之间的耦合关系,提高了灵活性和可扩展性。

在传统的面向对象编程中,类负责创建它所依赖的对象和管理自己的依赖。然而,控制反转改变了这种情况,它让外部容器或框架负责创建和管理这些依赖对象,而不是让类自己去创建。简单来说,控制反转就是将控制权类本身转移到外部容器,让容器来决定什么时候、如何创建对象以及如何注入它们的依赖。

依赖注入优势

依赖注入是控制反转的一种实现方式。通过依赖注入,外部容器负责将依赖对象注入到类中,而不是类自己去创建这些依赖。

  • 硬编码方式
EmailService.ts
ts
// EmailService.ts
class EmailService {
  send(to: string, message: string) {
    console.log(`发送邮件给 ${to}: ${message}`);
  }
}
UserService.ts
ts
// UserService.ts
import { EmailService } from './EmailService';

class UserService {
  private emailService: EmailService;

  constructor() {
    // ❌ 缺点:UserService 主动创建了 EmailService 实例
    // 如果以后想换成 SMS 模块,或者想在测试时不发真实邮件,就得改代码
    this.emailService = new EmailService();
  }

  register(email: string) {
    console.log('用户注册成功');
    this.emailService.send(email, '欢迎加入!');
  }
}
  • 使用依赖注入:
js
// 定义一个接口(TS 的灵魂所在)
interface NotificationService {
  send(to: string, message: string): void;
}

// 邮件实现
class EmailService implements NotificationService {
  send(to: string, message: string) { console.log(`邮件通知: ${to}`); }
}

// 短信实现
class SmsService implements NotificationService {
  send(to: string, message: string) { console.log(`短信通知: ${to}`); }
}

// UserService 变被动了
class UserService {
  // ✅ 优点:UserService 不关心具体是谁发,只要符合接口就行
  constructor(private readonly notifier: NotificationService) {}

  register(email: string) {
    this.notifier.send(email, '欢迎!');
  }
}

// --- 在应用入口处执行“注入” ---
const emailSvc = new EmailService();
const userSvc = new UserService(emailSvc); // 注入 Email 服务
userSvc.register('test@example.com');

依赖注入类型

构造器注入

通过构造函数将依赖项传递给对象

js
class Car {
  private engine: Engine;

  constructor(engine: Engine) {
    this.engine = engine; // engine是外部传入的依赖
  }

  start() {
    this.engine.run();
  }
}

属性注入

通过公开的属性将依赖项注入到对象中

js
class Car {
  engine: Engine;

  setEngine(engine: Engine) {
    this.engine = engine; // engine是外部传入的依赖
  }

  start() {
    this.engine.run();
  }
}

方法注入

依赖通过方法传入。

js
class Car {
  start(engine: Engine) {
    engine.run(); // engine是通过方法传入的依赖
  }
}