如何在tsyringe中实现策略模式动态注入且不污染依赖容器?
使用tsyringe实现策略模式:不污染容器的动态注入方案
问题场景
需要为Test类动态注入不同的策略实现(Thing1/Thing2),但不希望修改全局依赖容器,避免后续实例化时意外使用错误策略。
解决方案
1. 临时覆盖依赖(推荐)
利用tsyringe的container.resolve方法内置的overrides参数,临时指定当前实例的依赖,不会修改全局容器的注册信息。
首先给Test的构造参数定义一个统一令牌:
interface IThing { exec(): void; } @injectable() class Thing1 implements IThing { exec(): void { console.log('thing 1'); } } @injectable() class Thing2 implements IThing { exec(): void { console.log('thing 2'); } } @injectable() class Test { constructor( @inject('IThing') // 定义统一令牌 private readonly thing: IThing, ) { thing.exec(); } }
然后在实例化Test时,通过overrides临时注入对应策略:
// 注入Thing1的实例 const testWithThing1 = container.resolve(Test, { overrides: [ { token: 'IThing', useClass: Thing1 }, ], }); // 注入Thing2的实例 const testWithThing2 = container.resolve(Test, { overrides: [ { token: 'IThing', useClass: Thing2 }, ], });
这种方式仅对当前resolve生成的实例生效,完全不会污染全局容器。
2. 工厂类封装策略注入
如果需要更灵活的策略管理,可以创建工厂类来封装Test的实例化逻辑,手动传入策略实例:
@injectable() class TestFactory { createTest(thing: IThing): Test { // 若Test有其他依赖,可结合container.resolve和overrides return container.resolve(Test, { overrides: [{ token: 'IThing', useValue: thing }], }); } } // 使用方式 const factory = container.resolve(TestFactory); // 直接从容器获取策略实例并传入 const test1 = factory.createTest(container.resolve(Thing1)); const test2 = factory.createTest(container.resolve(Thing2));
这种方式将策略选择逻辑集中在工厂类中,代码可读性更强,同时避免全局容器污染。
3. 动态策略工厂(复杂场景适用)
如果策略实例的创建需要依赖其他服务,可以注册一个工厂令牌,根据参数动态返回对应策略:
// 注册策略工厂,用于根据类型生成对应策略实例 container.register('ThingStrategyFactory', { useFactory: (container) => { return (strategyType: 'Thing1' | 'Thing2') => { switch(strategyType) { case 'Thing1': return container.resolve(Thing1); case 'Thing2': return container.resolve(Thing2); default: throw new Error(`Unsupported strategy type: ${strategyType}`); } }; }, }); // 修改Test类,注入工厂和策略类型 @injectable() class Test { private readonly thing: IThing; constructor( @inject('ThingStrategyFactory') private readonly strategyFactory: (type: string) => IThing, @inject('TargetStrategy') private readonly targetStrategy: string, ) { this.thing = this.strategyFactory(this.targetStrategy); this.thing.exec(); } } // 实例化时指定目标策略 const test1 = container.resolve(Test, { overrides: [ { token: 'TargetStrategy', useValue: 'Thing1' }, ], }); const test2 = container.resolve(Test, { overrides: [ { token: 'TargetStrategy', useValue: 'Thing2' }, ], });
该方案适合策略依赖其他服务的复杂场景,同样不会修改全局容器的注册状态。
内容的提问来源于stack exchange,提问作者Anatole Lucet
相关产品推荐
相关产品推荐

