我正在尝试编写一个构建器模式,该模式通过多次实现接口来扩展。
这是我想要做的事情的代码片段。
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() //Ideally the call to .AdditionalBuilderFeature() would be allowed here. At the moment, it doesn't compile however...
.AdditionalBuilderFeature(/*Some param value*/)
.AdditionalBuilderFeature(/*Some param value*/);
}
}
}
如何创建可以通过接口扩展但仍设法返回主构建器类以保留调用为构建器实现的所有方法的能力的构建器模式?
在创建最小示例之前我尝试过的一件事是在类级别接受“Self”类型参数。由于构建器有时需要接受其他构建器作为方法参数,并且当可能存在多个实现时,使“Self”类型正确的复杂性导致这种情况失败。
借鉴带有继承的Builder设计模式的一些想法:有更好的方法吗? 我已经设法想出这个解决方案。然而,它在人体工程学方面损失了很多,因为你需要在每一步告诉它返回的正确类型。它还会导致编译器发出可能的空引用返回警告。
internal interface IBuilder<A, B>
{
Self BuilderCapability<Self>()
where Self : class, IBuilder<A, B>;
}
internal interface IConsumeOtherBuilder<A, B, C>
{
Self AdditionalBuilderFeature<Self>(IBuilder<B, C> obj)
where Self : class, IConsumeOtherBuilder<A, B, C>;
}
internal class ExampleBuilder : IBuilder<int, string>, IConsumeOtherBuilder<int, string, object>, IConsumeOtherBuilder<Guid, object, int>
{
public Self AdditionalBuilderFeature<Self>(IBuilder<string, object> obj)
where Self : class, IConsumeOtherBuilder<int, string, object>
{
Console.WriteLine($"{nameof(ExampleBuilder.AdditionalBuilderFeature)} with self type: {typeof(Self).FullName}");
obj.BuilderCapability<IBuilder<string, object>>();
return this as Self;
}
public Self AdditionalBuilderFeature<Self>(IBuilder<object, int> obj)
where Self : class, IConsumeOtherBuilder<Guid, object, int>
{
Console.WriteLine($"{nameof(ExampleBuilder.AdditionalBuilderFeature)} with self type: {typeof(Self).FullName}");
obj.BuilderCapability<IBuilder<object, int>>();
return this as Self;
}
public Self BuilderCapability<Self>()
where Self : class, IBuilder<int, string>
{
Console.WriteLine($"{nameof(ExampleBuilder.BuilderCapability)} with self type: {typeof(Self).FullName}");
return this as Self;
}
}
internal class OtherBuilders<A, B> : IBuilder<A, B>
{
public Self BuilderCapability<Self>()
where Self : class, IBuilder<A, B>
{
Console.WriteLine($"{nameof(OtherBuilders<A, B>.BuilderCapability)} with self type: {typeof(Self).FullName}");
return this as Self;
}
}
internal class Program
{
static void Main(string[] args)
{
var builder = new ExampleBuilder();
builder.BuilderCapability<ExampleBuilder>()
.AdditionalBuilderFeature<ExampleBuilder>(new OtherBuilders<string, object>())
.AdditionalBuilderFeature<ExampleBuilder>(new OtherBuilders<object, int>());
}
}
最后一点:此模式的一个版本目前主要用于在测试中构建数据。可能不适合生产代码的解决方案在这里可能是可以接受的。
虽然不是接口中协变返回类型的解决方法,但以下解决方案适用于我的问题。你的里程我的不同!
namespace BuilderChaining
{
internal interface IBuilder<A, B>
{
IBuilder<A, B> BuilderCapability();
}
internal interface IBuilderSelf<A, B, Self> : IBuilder<A, B>
{
new Self BuilderCapability();
}
internal interface IConsumeOtherBuilder<A, B, C>
{
IConsumeOtherBuilder<A, B, C> AdditionalBuilderFeature(IBuilder<B, C> obj);
}
internal interface IConsumeOtherBuilderSelf<A, B, C, Self> : IConsumeOtherBuilder<A, B, C>
{
new Self AdditionalBuilderFeature(IBuilder<B, C> obj);
}
internal class ExampleBuilder : IBuilderSelf<int, string, ExampleBuilder>, IConsumeOtherBuilderSelf<int, string, object, ExampleBuilder>, IConsumeOtherBuilderSelf<Guid, object, int, ExampleBuilder>
{
public ExampleBuilder AdditionalBuilderFeature(IBuilder<string, object> obj)
{
obj.BuilderCapability();
return this;
}
public ExampleBuilder AdditionalBuilderFeature(IBuilder<object, int> obj)
{
obj.BuilderCapability();
return this;
}
public ExampleBuilder BuilderCapability()
{
return this;
}
IConsumeOtherBuilder<int, string, object> IConsumeOtherBuilder<int, string, object>.AdditionalBuilderFeature(IBuilder<string, object> obj)
{
return AdditionalBuilderFeature(obj);
}
IConsumeOtherBuilder<Guid, object, int> IConsumeOtherBuilder<Guid, object, int>.AdditionalBuilderFeature(IBuilder<object, int> obj)
{
return AdditionalBuilderFeature(obj);
}
IBuilder<int, string> IBuilder<int, string>.BuilderCapability()
{
return BuilderCapability();
}
}
internal class OtherBuilders<A, B> : IBuilderSelf<A, B, OtherBuilders<A, B>>
{
public OtherBuilders<A, B> BuilderCapability()
{
return this;
}
IBuilder<A, B> IBuilder<A, B>.BuilderCapability()
{
return BuilderCapability();
}
}
internal class Program
{
static void Main()
{
var builder = new ExampleBuilder();
builder.BuilderCapability()
.AdditionalBuilderFeature(new OtherBuilders<string, object>())
.AdditionalBuilderFeature(new OtherBuilders<object, int>());
}
}
}