我正在使用 builder pattern ,已将重复代码提取到“帮助程序”类中,但重复代码的一个方面我仍然不满意。
构建器模式允许像这样链接实现代码:
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();
}
困扰我的是重复的return this
每次调用 Chain
后方法并认为我可以将其插入 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>
即
protected Builder<T> Chain(Action<T> action)
{
this.ChainFunc(action);
return this;
}
好吧,很公平,但在我的实现类中,我现在必须进行转换:
public CarBuilder Wheels(int wheels) =>
(CarBuilder)this.Chain(c => c.SetWheelCount(wheels));
所以我再次重复代码,所有方法现在都必须包含强制转换。将类类型从子类型传递到父类(super class)型感觉不对。
我想我可能在这里遗漏了一些基本的东西。我能否避免重复转换和必须从每个构建器实现方法中“返回这个”?
最佳答案
将逻辑保留在 protected 范围内的一种方法是添加一个被调用的静态方法而不是实例方法。静态方法可以使用隐式转换来返回调用者的类型
内部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);
关于c# - 从通用父类返回 `this` 需要在子类中强制转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43932828/