如何借助.NET Core DI装饰自定义工厂创建的对象?
带运行时参数的服务工厂如何结合容器驱动的装饰机制?
问题场景
假设我们有一个依赖仅能在运行时解析的参数的服务:
interface IFooService { void DoServicyStuff(); } class MyFooService : IFooService { private readonly string _peskyValue; public MyFooService(string somePeskyRuntimeArgument) { _peskyValue = somePeskyRuntimeArgument; } public void DoServicyStuff() { // 使用_peskyValue执行业务逻辑 } }
由于参数只能在运行时提供,我们通常会用工厂模式将构造参数转为方法参数:
interface IFooServiceFactory { IFooService CreateService(string runtimeParam); } class FooServiceFactory : IFooServiceFactory { public IFooService CreateService(string runtimeParam) { return new MyFooService(runtimeParam); } }
但这种模式下,为IFooService添加装饰器会遇到一系列问题:
- 直接调用容器
GetRequiredService<IFooService>会因找不到string类型的注册而失败; - 手动在工厂内创建装饰器耦合度极高,新增装饰器必须修改工厂代码;
- 为每个服务装饰器编写对应的工厂装饰器会大幅增加代码复杂度。
现有手动方案的弊端
1. 工厂内手动创建装饰器
耦合度极高,新增装饰器必须修改工厂核心逻辑:
public IFooService CreateService(string runtimeParam) { return new LoggingFooService(new MyFooService(runtimeParam)); }
2. 工厂装饰器模式
需为每个服务装饰器编写对应的工厂装饰器,实现繁琐且重复:
abstract class FooServiceFactoryDecorator : IFooServiceFactory { protected readonly IFooServiceFactory _innerFactory; protected FooServiceFactoryDecorator(IFooServiceFactory innerFactory) { _innerFactory = innerFactory; } public virtual IFooService CreateService(string runtimeParam) { return _innerFactory.CreateService(runtimeParam); } } class LoggingFooServiceFactory : FooServiceFactoryDecorator { public LoggingFooServiceFactory(IFooServiceFactory innerFactory) : base(innerFactory) { } public override IFooService CreateService(string runtimeParam) { return new LoggingFooService(_innerFactory.CreateService(runtimeParam)); } } // 注册时需装饰工厂而非服务 services.AddTransient<IFooServiceFactory, FooServiceFactory>() .Decorate<IFooServiceFactory, LoggingFooServiceFactory>();
3. 泛化工厂装饰器
虽能复用逻辑,但维护难度大,添加装饰器的语法不够简洁:
class DecoratedFooServiceFactory<TDecorator> : FooServiceFactoryDecorator where TDecorator : IFooService { private readonly IServiceProvider _serviceProvider; public DecoratedFooServiceFactory(IFooServiceFactory innerFactory, IServiceProvider serviceProvider) : base(innerFactory) { _serviceProvider = serviceProvider; } public override IFooService CreateService(string runtimeParam) { return ActivatorUtilities.CreateInstance<TDecorator>( _serviceProvider, _innerFactory.CreateService(runtimeParam)); } } // 注册时需指定泛型参数 services.AddTransient<IFooServiceFactory, FooServiceFactory>() .Decorate<IFooServiceFactory, DecoratedFooServiceFactory<LoggingFooService>>();
以上方案均无法直接使用Scrutor的.Decorate<IFooService, TDecorator>简洁语法,且后续弃用工厂时需重新配置所有装饰器。
优雅实现方案
核心思路是让容器负责管理装饰器链,同时通过工厂委托传递运行时参数,无需手动编写装饰器相关的工厂类。
步骤1:注册服务与装饰器
首先注册底层服务MyFooService,然后为IFooService注册一个依赖运行时参数的创建逻辑,最后用Scrutor添加装饰器:
// 注册底层服务(自身类型) services.AddTransient<MyFooService>(); // 注册接收运行时参数的IFooService创建委托 services.AddTransient<Func<string, IFooService>>(sp => runtimeParam => { // 创建底层服务实例 var baseService = ActivatorUtilities.CreateInstance<MyFooService>(sp, runtimeParam); // 让容器为该实例应用所有已注册的装饰器 return sp.GetRequiredService<IDecoratorFactory>().Decorate<IFooService>(baseService); }); // 使用Scrutor添加装饰器(简洁语法) services.Decorate<IFooService, LoggingFooService>(); services.Decorate<IFooService, ValidationFooService>(); // 新增装饰器只需一行代码
步骤2:简化工厂实现
现在工厂只需依赖Func<string, IFooService>委托,无需直接操作容器或手动创建装饰器:
class FooServiceFactory : IFooServiceFactory { private readonly Func<string, IFooService> _fooServiceCreator; public FooServiceFactory(Func<string, IFooService> fooServiceCreator) { _fooServiceCreator = fooServiceCreator; } public IFooService CreateService(string runtimeParam) { return _fooServiceCreator(runtimeParam); } } // 注册工厂 services.AddTransient<IFooServiceFactory, FooServiceFactory>();
关键说明
- 容器自动维护
IFooService的装饰链,新增装饰器只需调用.Decorate<IFooService, TDecorator>(),无需修改工厂代码; - 装饰器自身的依赖(如
ILogger<T>)会由容器自动注入,无需手动处理; - 后续若要弃用工厂,只需直接注入
Func<string, IFooService>或调整注册逻辑,无需重新配置装饰器。
内容的提问来源于stack exchange,提问作者julealgon
相关产品推荐
相关产品推荐

