如何让C#建造者模式实现接口后仍保留链式调用能力?
可通过接口扩展的链式建造者模式实现方案
问题描述
需要实现一个通过多接口扩展功能的建造者模式,要求调用任意接口方法后,返回的对象仍能链式调用所有实现的接口方法。当前代码中,调用BuilderCapability()后返回的是IBuilder<int, string>类型,无法直接链式调用AdditionalBuilderFeature()方法。
原始问题代码:
namespace BuilderChaining { internal interface IBuilder<A, B> { IBuilder<A, B> BuilderCapability(); } internal interface IConsumeOtherBuilder<A, B, C> { IConsumeOtherBuilder<A, B, C> AdditionalBuilderFeature(IBuilder<B, C> obj); } internal class ExampleBuilder : IBuilder<int, string>, IConsumeOtherBuilder<int, string, object>, IConsumeOtherBuilder<Guid, object, int> { public IConsumeOtherBuilder<int, string, object> AdditionalBuilderFeature(IBuilder<string, object> obj) { return this; } public IConsumeOtherBuilder<Guid, object, int> AdditionalBuilderFeature(IBuilder<object, int> obj) { return this; } public IBuilder<int, string> BuilderCapability() { return this; } } internal class Program { static void Main(string[] args) { var builder = new ExampleBuilder(); builder.BuilderCapability() // 此处无法继续链式调用AdditionalBuilderFeature() .AdditionalBuilderFeature(/*Some param value*/) .AdditionalBuilderFeature(/*Some param value*/); } } }
现有尝试的缺陷
曾尝试通过泛型Self参数解决,但该方案需要每次调用方法时显式指定返回类型,易用性差,且会触发空引用返回警告:
// 简化后的问题代码片段 internal interface IBuilder<A, B> { Self BuilderCapability<Self>() where Self : class, IBuilder<A, B>; } // 调用时必须指定泛型类型 builder.BuilderCapability<ExampleBuilder>() .AdditionalBuilderFeature<ExampleBuilder>(new OtherBuilders<string, object>());
最优解决方案:递归泛型约束
通过给每个接口添加递归泛型约束,让接口方法直接返回具体的建造者实现类,从而保留完整的类型信息,支持无额外指定的链式调用。
1. 修改接口定义
为每个接口添加Self泛型参数,约束为当前接口的实现类:
internal interface IBuilder<A, B, out Self> where Self : IBuilder<A, B, Self> { Self BuilderCapability(); } internal interface IConsumeOtherBuilder<A, B, C, out Self> where Self : IConsumeOtherBuilder<A, B, C, Self> { Self AdditionalBuilderFeature(IBuilder<B, C, object> obj); }
2. 实现建造者类
让ExampleBuilder实现接口时,将Self参数指定为自身,所有方法返回ExampleBuilder类型:
internal class ExampleBuilder : IBuilder<int, string, ExampleBuilder>, IConsumeOtherBuilder<int, string, object, ExampleBuilder>, IConsumeOtherBuilder<Guid, object, int, ExampleBuilder> { public ExampleBuilder AdditionalBuilderFeature(IBuilder<string, object, object> obj) { // 此处添加业务逻辑 return this; } public ExampleBuilder AdditionalBuilderFeature(IBuilder<object, int, object> obj) { // 此处添加业务逻辑 return this; } public ExampleBuilder BuilderCapability() { // 此处添加业务逻辑 return this; } }
3. 实现辅助建造者类
其他辅助建造者同样遵循接口约束:
internal class OtherBuilders<A, B> : IBuilder<A, B, OtherBuilders<A, B>> { public OtherBuilders<A, B> BuilderCapability() { // 此处添加业务逻辑 return this; } }
4. 链式调用示例
此时可以直接实现无额外泛型指定的链式调用:
internal class Program { static void Main(string[] args) { var builder = new ExampleBuilder(); builder.BuilderCapability() .AdditionalBuilderFeature(new OtherBuilders<string, object>()) .AdditionalBuilderFeature(new OtherBuilders<object, int>()); } }
方案优势
- 无需显式指定泛型类型,调用体验简洁
- 所有方法返回具体建造者类,保留完整的方法调用能力
- 符合测试数据构建的场景需求,即使是测试专用方案也足够优雅
内容的提问来源于stack exchange,提问作者PurpleKoala
相关产品推荐
相关产品推荐

