Фундаментальная проблема здесь заключается в том, что пользовательский интерфейс должен переводить потребности пользователя в удобный для машин формат - в данном случае, одну из ваших стратегий сортировки. Следовательно, некоторый код где-то должен посмотреть на вводимые пользователем данные и решить, возможно, с помощью предложения if
, какой логический путь выбрать и какой тип стратегии создать. Этот аспект программирования пользовательского интерфейса неизбежен.
Самое безопасное и разумное место для размещения такого кода - это как можно ближе к элементам управления пользовательского интерфейса. Для этого есть несколько причин:
Размещая код перевода в самом модуле пользовательского интерфейса, вы избегаете других зависимостей, формирующих код, от него.
Дизайн пользовательского интерфейса, как правило, меняется быстрее, чем бизнес-правила, поскольку пользователи находят бесконечные новые способы решения одной и той же проблемы. Когда что-то меняется одновременно, объединение их в исходный код облегчает управление кодом и сборкой, вопросы обеспечения качества и развертывания.
Уродство кода имеет смысл только в контексте дизайна пользовательского интерфейса, поэтому их объединение облегчает будущим разработчикам понимание происходящего.
Что касается шаблонов проектирования, то это одна из немногих областей, где я бы позволил разработчикам писать код, который выглядит немного спагетти-иш. Реальность требований заключается в том, что дизайн должен быть оптимизирован с учетом человеческого фактора, а не факторов машины и архитектурной элегантности. Другими словами, использование switch/case
- это нормально.
При этом размещение switch/case
вокруг различных вызовов для извлечения данных проблематично, поскольку обычно в этих вызовах есть логика, которую вы не хотели бы дублировать. Таким образом, шаблон стратегии не плохой. Я бы предложил фабричный шаблон, который может возвращать стратегию, учитывая серию пользовательских входных данных, возможно передаваемых в DTO.
На высоком уровне это может выглядеть так:
var dto = new GetSortedPostsRequestDto
{
StartDate = inputForm.StartDatePicker.SelectedDate,
SortMode = inputForm.GetSelectedSortMode()
};
var strategy = GetSortStrategy(dto);
var results = unitOfWork.GetSortedPosts(strategy);
Этот подход особенно эффективен, когда DTO приходит извне вашего кода на C #, например. если он был собран Javascript и отправлен через вызов REST.
Метод GetSortStrategy()
- это место, где будет существовать ваш case/switch
. Хотя фабричный класс не обязательно исключен, его обычно можно записать как не универсальный фабричный метод.
ISortStrategy GetSortStrategy(GetSortedPostsRequestDto dto)
{
switch case dto.SortMode
{
case SortMode.New: return new SortByNewStrategy();
case SortMode.Top: return new SortByTopStrategy();
case SortMode.Recent: return new SortByRecentStrategy(dto.StartDate);
//etc.
}
}
Обратите внимание, что этот шаблон позволяет вам передавать startDate
тогда и только тогда, когда он применяется к выбору пользователя.