使用继承的生成器模式



我有CommonRequestBuilderSpecificRequestBuilder,它们看起来像这样。

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();

CommonRequestBuilderWithDetails()的默认实现还有一个额外的好处,即在处理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
{
// ...
}

相关内容

  • 没有找到相关文章

最新更新