我有CommonRequestBuilder
和SpecificRequestBuilder
,它们看起来像这样。
public class CommonRequestBuilder
{
protected readonly BigRequest _request;
public CommonRequestBuilder()
{
_request = new BigRequest();
}
public CommonRequestBuilder WithExtras()
{
// add extra stuff to _request
return this;
}
public BigRequest Build()
{
return _request;
}
}
public class SpecificRequestBuilder : CommonRequestBuilder
{
public SpecificRequestBuilder WithDetails()
{
// add some stuff to _request
return this;
}
public BigRequest Build()
{
return _request;
}
}
这个模式的问题是,如果我使用这样的SpecificRequestBuilder:
_specificRequestBuilder.WithExtras().WithDetails(); // WithDetails() is not found
在上面的代码中,WithDetails()
无法解析,因为我正在从WithExtras()
中获取基类。我可以重新安排方法使其工作,但有没有一种方法可以更新类,使任何顺序都工作?
您必须在SpecificRequestBuilder
中使用new
关键字才能获得具有不同返回类型的方法:
public class SpecificRequestBuilder : CommonRequestBuilder
{
public SpecificRequestBuilder WithDetails()
{
// add some stuff to _request
return this;
}
public new SpecificRequestBuilder WithExtras()
{
return (SpecificRequestBuilder)base.WithExtras();
}
}
在线演示:https://dotnetfiddle.net/tU4hEM
在C#9.0(这是最新版本,所以请确保您有它,它与VS 16.8.2一起提供(中,您可以使用协变重写,这将非常适合这里。这将允许您进行这样的更改:
只需将方法WithExtras
设为虚拟方法,并在基类中用返回类型SpecificRequestBuilder
覆盖它,就像下面的一样
public class CommonRequestBuilder
{
protected readonly BigRequest _request;
public CommonRequestBuilder()
{
_request = new BigRequest();
}
public virtual CommonRequestBuilder WithExtras()
{
// add extra stuff to _request
return this;
}
public BigRequest Build()
{
return _request;
}
}
public class SpecificRequestBuilder : CommonRequestBuilder
{
public override SpecificRequestBuilder WithExtras()
{
base.WithExtras();
return this;
}
public SpecificRequestBuilder WithDetails()
{
return this;
}
public BigRequest Build()
{
return _request;
}
}
Now语句
_specificRequestBuilder.WithExtras().WithDetails();
变得完全有效。
就我个人而言,我会实现一种真正的多态方法。
请求构建器应该是接口的,那么构建器的具体类型是什么并不重要:
interface IRequestBuilder
{
IRequestBuilder WithExtras();
IRequestBuilder WithDetails();
BigRequest Build();
}
您仍然可以提供默认实现:
public class CommonRequestBuilder : IRequestBuilder
{
protected readonly BigRequest _request;
public CommonRequestBuilder()
{
_request = new BigRequest();
}
public virtual IRequestBuilder WithExtras()
{
// add extra stuff to _request
return this;
}
// Default implementation
IRequestBuilder IRequestBuilder.WithDetails() => this;
public virtual BigRequest Build()
{
return _request;
}
}
并使其更加具体:
public class SpecificRequestBuilder : CommonRequestBuilder
{
public IRequestBuilder WithDetails()
{
// add some stuff to _request
return this;
}
}
现在您可以使用任何您喜欢的实现:
IRequestBuilder builder = new SpecificRequestBuilder().WithExtras().WithDetails();
CommonRequestBuilder
中WithDetails()
的默认实现还有一个额外的好处,即在处理CommonRequestBuilder
变量时不允许调用该方法,因为它什么都不做。
您可以在基上声明WithDetails为可以覆盖的虚拟方法。
public virtual CommonRequestBuilder WithDetails()
构建也必须是虚拟的基础上被覆盖
public BigRequest Build()
您会遇到这样的问题:派生类上的WithDetails无法返回SpecialRequestBuilder。
我会创建一个可以通过各种实现来实现的接口。除非坚持使用CommonRequestBuilder(或BaseRequestBuilder(就足够了。
public interface IRequestBuilder
{
IRequestBuilder WithExtras();
IRequestBuilder WithDetails();
BigRequest Build();
}
public class CommonRequestBuilder : IRequestBuilder
{
// ...
}
public class SpecificRequestBuilder : CommonRequestBuilder, IRequestBuilder
{
// ...
}