如何在Angular中按需动态创建服务的全新实例?
解决方案:在Angular中动态创建Command实例实现撤销/重做
核心思路
要实现运行时(如按钮点击)动态创建带依赖注入的Command实例,不能直接用new(无法自动注入依赖),也不能用Injector.get()(返回单例)。可以通过创建子注入器的方式,每次生成全新的Command实例,同时保留依赖注入能力。
步骤1:实现Command工厂服务
这个工厂负责创建Command的新实例,利用Angular的Injector创建子注入器来确保每次都是新实例:
import { Injectable, Injector, Type } from '@angular/core'; import { Command } from './command.interface'; // 假设你有Command基类/接口 @Injectable({ providedIn: 'root' }) export class CommandFactory { constructor(private injector: Injector) {} // 泛型方法,支持创建任意Command子类的实例 createCommand<T extends Command>(commandType: Type<T>): T { // 创建子注入器,继承父注入器的所有依赖 const childInjector = Injector.create({ providers: [{ provide: commandType }], parent: this.injector }); // 从子注入器获取新实例 return childInjector.get(commandType); } }
步骤2:定义你的Command类
修正原示例中的语法错误:
import { Injectable } from '@angular/core'; import { Command } from './command.interface'; import { SomeService } from './some.service'; @Injectable() export class MyCommand extends Command { constructor(private someService: SomeService) { super(); // 如果Command是抽象类,记得调用父类构造函数 } public execute(): void { const value = this.someService.getSomeValue(); // 执行具体命令逻辑 } // 实现撤销逻辑(Command模式必备) public undo(): void { // 撤销execute执行的操作 } }
步骤3:在组件中按需创建实例
在按钮点击等交互场景下,调用工厂创建新实例,并保存到历史记录用于撤销/重做:
import { Component } from '@angular/core'; import { CommandFactory } from './command.factory'; import { MyCommand } from './my.command'; import { Command } from './command.interface'; @Component({ selector: 'app-my-component', template: ` <button (click)="onExecuteCommand()">执行命令</button> <button (click)="onUndo()" [disabled]="commandHistory.length === 0">撤销</button> ` }) export class MyComponent { private commandHistory: Command[] = []; constructor(private commandFactory: CommandFactory) {} onExecuteCommand(): void { // 动态创建新的MyCommand实例 const command = this.commandFactory.createCommand(MyCommand); command.execute(); // 保存到历史记录 this.commandHistory.push(command); } onUndo(): void { const lastCommand = this.commandHistory.pop(); if (lastCommand) { lastCommand.undo(); } } }
方案适配性说明
- 完全避开
Injector.get()的单例问题,每次调用createCommand都会生成全新的实例 - 实例在交互触发时动态创建,而非组件初始化阶段
- Command类能正常注入Angular服务(如示例中的
SomeService),满足依赖注入需求 - 无需依赖transient providers,完全由业务逻辑控制实例创建时机
内容的提问来源于stack exchange,提问作者Matthew Holmes
相关产品推荐
相关产品推荐

