如何使用Autofac实现责任链设计模式?含依赖注入配置问题
Autofac实现责任链模式的配置方案
问题背景
尝试用Autofac实现责任链设计模式,运行时收到Autofac组件未注册的提示。已知可以用RegisterDecorator配置,但该方法不适用于所有责任链场景,想了解如果使用SetNextHandler方法时该如何配置,以及是否有更合适的替代方案。
先修正代码中的错误
你的ConcreteHandlerB构造函数存在笔误,会导致编译失败,需修正为:
namespace ChainOfResponsibilitySample; internal class ConcreteHandlerB : IHandler { private readonly IHandler _next; public ConcreteHandlerB(IHandler next) { // 原代码误写为ConcreteHandlerA _next = next; } public void Handle() { // do something _next.Handle(); } }
当前注册方式的问题
你使用的WithParameter直接解析IHandler会触发循环依赖:当Autofac解析ConcreteHandlerA时,需要注入IHandler,而最后注册的ConcreteHandlerA是IHandler的默认实现,会引发递归解析,最终抛出组件未注册或循环依赖异常。
解决方案
方案1:命名服务手动组装责任链(适合灵活控制顺序/使用SetNextHandler的场景)
这种方式完全手动控制链的组装逻辑,适合需要动态调整顺序、或者处理器通过SetNextHandler方法设置下一个节点的场景:
修改AutofacModule注册逻辑
using Autofac; namespace ChainOfResponsibilitySample; internal class AutofacModule : Module { protected override void Load(ContainerBuilder builder) { // 1. 将每个处理器注册为命名服务,避免覆盖默认IHandler builder.RegisterType<ConcreteHandlerC>().Named<IHandler>("HandlerC"); builder.RegisterType<ConcreteHandlerB>().Named<IHandler>("HandlerB"); builder.RegisterType<ConcreteHandlerA>().Named<IHandler>("HandlerA"); // 2. 手动组装责任链:A → B → C builder.Register(ctx => { var handlerC = ctx.ResolveNamed<IHandler>("HandlerC"); var handlerB = ctx.ResolveNamed<IHandler>("HandlerB", new TypedParameter(typeof(IHandler), handlerC)); var handlerA = ctx.ResolveNamed<IHandler>("HandlerA", new TypedParameter(typeof(IHandler), handlerB)); return handlerA; }).As<IHandler>(); // 将组装好的根处理器注册为IHandler默认实现 base.Load(builder); } }
适配SetNextHandler的场景
如果处理器通过SetNextHandler方法而非构造函数注入下一个节点,修改组装逻辑即可:
// 假设处理器接口新增SetNextHandler方法 public interface IHandler { void Handle(); void SetNextHandler(IHandler next); } // 组装时调用方法设置下一个节点 builder.Register(ctx => { var handlerC = ctx.ResolveNamed<IHandler>("HandlerC"); var handlerB = ctx.ResolveNamed<IHandler>("HandlerB"); handlerB.SetNextHandler(handlerC); var handlerA = ctx.ResolveNamed<IHandler>("HandlerA"); handlerA.SetNextHandler(handlerB); return handlerA; }).As<IHandler>();
方案2:使用RegisterDecorator(适合固定顺序的装饰器式责任链)
RegisterDecorator适合无状态、顺序固定的责任链场景,本质是装饰器模式的实现,代码更简洁:
protected override void Load(ContainerBuilder builder) { // 注册最终节点 builder.RegisterType<ConcreteHandlerC>().As<IHandler>(); // 用B装饰现有IHandler(即C) builder.RegisterDecorator<IHandler>((ctx, inner) => new ConcreteHandlerB(inner), fromKey: null); // 用A装饰现有IHandler(即B→C) builder.RegisterDecorator<IHandler>((ctx, inner) => new ConcreteHandlerA(inner), fromKey: null); }
注意:这种方式要求责任链是严格的装饰器结构(每个处理器仅依赖下一个节点),如果需要动态调整顺序、或者处理器有状态需要单独管理,方案1更合适。
方案3:注册顺序+InstancePerDependency(不推荐)
如果坚持用构造函数注入且不使用命名服务,可以调整注册顺序并指定生命周期,但这种方式依赖注册顺序,后续维护容易出错:
protected override void Load(ContainerBuilder builder) { // 先注册最终节点,InstancePerDependency确保每次解析都是新实例 builder.RegisterType<ConcreteHandlerC>() .As<IHandler>() .InstancePerDependency(); // 注册B,解析IHandler时会拿到C builder.RegisterType<ConcreteHandlerB>() .As<IHandler>() .InstancePerDependency() .WithParameter((pi, ctx) => pi.ParameterType == typeof(IHandler), (pi, ctx) => ctx.Resolve<IHandler>()); // 注册A,解析IHandler时会拿到B builder.RegisterType<ConcreteHandlerA>() .As<IHandler>() .InstancePerDependency(); }
内容的提问来源于stack exchange,提问作者fizch
相关产品推荐
相关产品推荐

