[英]Returning `this` from generic parent class requires cast in child
我正在使用构建器模式 ,将重复的代码提取到“帮助器”类中,但是重复代码的一个方面我仍然不满意。
构建器模式允许链接实现代码,如下所示:
Car car = new CarBuilder().Wheels(4).Convertible().Build();
每个方法CarBuilder
, Wheels
和Convertible
返回构建器类的相同实例( return this
), Build
方法返回新实例化的Car
。
这是我对通用构建器类的尝试:
public class Builder<T> where T : class
{
private Func<T, T> func;
protected void SetInstantiator(Func<T, T> f) => this.func = f;
protected void Chain(Action<T> action)
{
this.ChainFunc(action);
}
private ChainFunc(Action<T> action)
{
// SNIPPED
}
protected T Instantiate() => this.func(null);
}
这是我的通用构建器的实现:
public class CarBuilder : Builder<Car>
{
public CarBuilder()
{
this.SetInstantiator(c => new Car());
return this;
}
public CarBuilder Wheels(int wheels)
{
this.Chain(c => c.SetWheelCount(wheels));
return this;
}
public CarBuilder Convertible()
{
this.Chain(c => c.RetractableRoof = true);
return this;
}
public Car Build() => this.Instantiate();
}
困扰我的是每次调用Chain
方法后重复return this
并认为我可以将其推入Chain
方法本身,即我想编写这样的代码:
public CarBuilder Wheels(int wheels) =>
this.Chain(c => c.SetWheelCount(wheels));
在构建器类中,我尝试将返回类型从void
更改为Builder
:
protected Builder Chain(Action<T> action)
{
this.ChainFunc(action);
return this;
}
...但是编译器说返回类型必须是Builder<T>
ie
protected Builder<T> Chain(Action<T> action)
{
this.ChainFunc(action);
return this;
}
好吧,公平,但在我的实现类中,我现在必须做一个演员:
public CarBuilder Wheels(int wheels) =>
(CarBuilder)this.Chain(c => c.SetWheelCount(wheels));
所以我再次重复代码,所有方法现在都必须包含一个强制转换。 将类类型从子类型传递给超类型感觉不对。
我想我可能会遗漏一些基本的东西。 我可以避免重复演员表并且必须从每个构建器实现方法中“返回”吗?
不要把Chain
放在基类中。 相反,将其作为通用扩展方法:
public static TBuilder Chain<TBuilder, TObject>(this TBuilder @this, Action<TObject> a)
where TBuilder: Builder<TObject>
=> ...
将逻辑保留在受保护范围内的一种方法是添加一个被调用的静态方法而不是实例方法。 静态方法可以使用隐式转换来返回调用者的类型
在Builder<T>
内部Builder<T>
protected void Chain(Action<T> action)
{
//local chain logic
}
protected static BT Chain<BT>(BT builder, Action<T> action)
where BT:Builder<T>
{
builder.Chain(action);
return builder;
}
在CarBuilder
调用:
public CarBuilder Wheels(int wheels) => Chain(this , c => c.SetWheelCount(wheels));
public CarBuilder Convertible() => Chain(this, c => c.RetractableRoof = true);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.