从通用父类返回`this`需要在子

时间:2017-05-12 08:21:29

标签: c# builder-pattern

我正在使用builder pattern,将重复的代码提取到'帮助'类中,但重复代码的一个方面我仍然不满意。

构建器模式允许用户链接实现代码:

Car car = new CarBuilder().Wheels(4).Convertible().Build();

每个方法CarBuilderWheelsConvertible都返回构建器类(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));

所以我再次重复代码,所有方法现在都必须包含一个强制转换。将类类型从子类型传递给超类型感觉不对。

我想我可能会遗漏一些基本的东西。我可以避免重复演员并且必须从每个构建器实现方法中“返回”吗?

1 个答案:

答案 0 :(得分:1)

不要将Chain放在基类中。相反,将其作为通用扩展方法:

public static TBuilder Chain<TBuilder, TObject>(this TBuilder @this, Action<TObject> a)
 where TBuilder: Builder<TObject>
 => ...