Я создаю серию строителей, чтобы очистить синтаксис, который создает классы домена для моих макетов как часть улучшения наших общих модульных тестов. Мои разработчики по существу заполняют класс домена (например, Schedule
) с некоторыми значениями, определяемыми путем вызова соответствующего WithXXX
и объединения их вместе.Дизайн шаблона Builder с наследованием: есть ли лучший способ?
Я столкнулся с некоторой общности среди моих строителей, и я хочу отвлечь это в базовом классе, чтобы увеличить повторное использование кода. К сожалению, то, что я в конечном итоге выглядит как:
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 this
в WithId(int)
методом BaseBuilder
.
Обнаруживает дочерний тип с свойством abstract BLDR This { get; }
Мой единственный вариант здесь, или я пропустил какой-то синтаксический трюк?
Update (так как я могу показать, почему я делаю это немного более ясно):
Конечным результатом является то, чтобы строители, которые строят профилированные классы домена, которые можно было бы ожидать, чтобы извлечь из базы данных в [ программист]. Нет ничего плохого в том, что ...
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()
);
Yup похоже, что мы застряли с "abstract T Это {get;}" Я соглашусь и закрываю, так как я думаю, что решение - это все, что доступно. – cfeduke 2008-10-29 14:50:11
Я пытаюсь найти относительно четкий способ создания строителей и нашел эту статью (http://www.codeproject.com/Articles/240756/Hierarchical-Implementing-the-Bolchs-Builder-Pat). Он предлагает бросить его один раз (защищенный BLDR _this; _this = (BLDR) this; return _this;), но я не могу понять, почему автор добавил класс WindowBuilder: WindowBuilder {} (Посмотрите полный пример на в нижней части статьи). В этом сообщении я вижу почти тот же шаблон, но cfeduke использует класс ScheduleIntervalBuilder: BaseBuilder ... –
2012-06-22 21:59:49