我正在创建一系列构建器,以清理为我的模拟创建域类的语法,以此作为改进整体单元测试的一部分。我的构建器实质上是通过调用适当的Schedule并将它们链接在一起而确定的一些值来填充域类(例如WithXXX)。

我在构建器中遇到了一些共性,我想将其抽象为基类以增加代码重用性。不幸的是,我最终看起来像:

public abstract class BaseBuilder<T,BLDR> where BLDR : BaseBuilder<T,BLDR>
                                          where T : new()
{
    public abstract T Build();

    protected int Id { get; private set; }
    protected abstract BLDR This { get; }

    public BLDR WithId(int id)
    {
        Id = id;
        return This;
    }
}

特别注意protected abstract BLDR This { get; }

域类构建器的示例实现为:
public class ScheduleIntervalBuilder :
    BaseBuilder<ScheduleInterval,ScheduleIntervalBuilder>
{
    private int _scheduleId;
    // ...

    // UG! here's the problem:
    protected override ScheduleIntervalBuilder This
    {
        get { return this; }
    }

    public override ScheduleInterval Build()
    {
        return new ScheduleInterval
        {
            Id = base.Id,
            ScheduleId = _scheduleId
                    // ...
        };
    }

    public ScheduleIntervalBuilder WithScheduleId(int scheduleId)
    {
        _scheduleId = scheduleId;
        return this;
    }

    // ...
}

因为BLDR不是BaseBuilder类型,所以我不能在return thisWithId(int)方法中使用BaseBuilder

在这里,使用属性abstract BLDR This { get; }公开子类型是我唯一的选择,还是我缺少一些语法技巧?

更新(因为我可以更清楚地说明为什么这样做):

最终结果是让构建器构建概要分析的 Realm 类,人们期望这些 Realm 类以[程序员]可读格式从数据库中检索。没错...
mock.Expect(m => m.Select(It.IsAny<int>())).Returns(
    new Schedule
    {
        ScheduleId = 1
        // ...
    }
);

因为它已经很可读了。备用构建器语法为:
mock.Expect(m => m.Select(It.IsAny<int>())).Returns(
    new ScheduleBuilder()
        .WithId(1)
        // ...
        .Build()
);

我从使用构建器(并实现所有这些WithXXX方法)中寻找的优势是抽象出复杂的属性创建(使用正确的Lookup.KnownValues自动扩展我们的数据库查找值,而不会明显打击数据库)并使构建器提供通常可重用的域类的测试配置文件...
mock.Expect(m => m.Select(It.IsAny<int>())).Returns(
    new ScheduleBuilder()
        .AsOneDay()
        .Build()
);

最佳答案

我只能说,如果有办法,我也想知道—我在Protocol Buffers port中完全使用了这种模式。实际上,我很高兴看到其他人采用了它-这意味着我们至少在某种程度上是对的!

关于c# - 具有继承: is there a better way?的生成器设计模式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/244772/

10-11 02:10