Как более чище обращаться с огромным заводом
-
21-08-2019 - |
Вопрос
Моя команда разработчиков столкнулась с проблемой дизайна.Я надеюсь, что кто-нибудь сможет помочь мне немного почистить эту часть архитектуры.
В моей системе у меня есть перечисление с 250 элементами [один элемент представляет собой отдельный выпадающий список].Чтобы заполнить выпадающие списки в любом заданном окне, эта форма отправляет элементы перечисления, которые относятся к необходимым выпадающим спискам, и возвращается раскрывающаяся информация.
Другими словами, скажем, например, у нас есть 3 окна.Окно A имеет выпадающие списки X, Y и Z.Окно B имеет выпадающие списки W, X и Y, а окно C имеет выпадающие списки T, U и W.Мое перечисление DropDownType будет состоять из T, U, W, X, Y, Y и Z.Итак, для указанного окна, учитывая выпадающие списки в этом окне, я запрашиваю, чтобы данные отображались в этих выпадающих списках.
Это упрощенный пример, потому что мое приложение состоит из> 250 различных выпадающих списков.
Как вы можете себе представить, у меня есть заводская настройка для возврата данных для каждого выпадающего списка.И эта фабрика вызывается для каждого запрошенного выпадающего списка.
switch (dropDownType)
{
case DropDownType.T:
return (from t in dataContext.GetTable<TableOne>()
select new DropDownDto
{
DropDownDisplayName = t.ColumnA,
DropDownValue = t.ColumnB
}).ToList();
case DropDownType.U:
return (from u in dataContext.GetTable<TableTwo>()
select new DropDownDto
{
DropDownDisplayName = u.ColumnC,
DropDownValue = u.ColumnD
}).ToList();
// etc...
}
Поскольку у меня так много участников в этом перечислении, кто-нибудь знает о более элегантном способе кодирования этого?Как вы думаете, было бы полезно преобразовать это в фабричные методы (но тогда нам пришлось бы беспокоиться о 250 отдельных файлах в нашем исходном коде ...)?Есть ли другой шаблон, который более полезен?Просто наличие этого ОГРОМНОГО оператора switch становится неуправляемым.
Любая помощь очень ценится.Заранее спасибо!
Решение
Вы могли бы создать Dictionary<DropDownType, DropDownDtoDelegate>
при этом каждая запись содержит запись enum в качестве ключа и делегат для извлечения выпадающих данных в качестве значения.Это позволило бы вам сохранить каждый метод, возвращающий выпадающий список, отдельно и вне инструкции huge switch.Затем у вас будет один метод для извлечения делегата, его выполнения и возврата данных выпадающего списка.
Другие советы
Есть несколько решений таких проблем.
Вы могли бы использовать словарь для сопоставления выпадающих списков с вашими данными.
Вы даже можете рассмотреть возможность переноса этих картографических данных в базу данных.Объем данных может как раз соответствовать этому решению.
Чтобы удалить дополнительные ключи в форме вашего перечисления, подумайте об использовании названий выпадающих списков в качестве ключа.
Вот действительно хороший блог, посвященный смежным проблемам и предлагающий аналогичные решения.
Вернемся к основам - Жизнь после напоминания о структурах данных в стиле If, For и Switch
Одним из вариантов может заключаться в использовании отражения для обработки значения enum.Если у вас есть согласованный стандарт именования для всех задействованных классов, возможно, существует способ динамически генерировать имя таблицы / коллекции для запроса и имя возвращаемого DTO.Это потребует немного "служебного" кода, чтобы заставить его работать, но как только вы это сделаете, он потенциально может работать для всех разных таблиц.
Я бы использовал DynamicMethod для генерации кода во время выполнения для каждого элемента в перечислении.Это должно быть кэшировано в словаре и генерироваться по требованию.
С помощью атрибута вы можете задать Сущность, используемую в каждом перечислении, и эти 2 необходимых свойства.
Я могу представить себе что-то подобное этому.
enum DropDownType
{
[Configuration(Type = typeof(TableOne), DisplayNameProperty = "ColumnA", ValueProperty = "ColumnB")]
T,
[Configuration(Type = typeof(TableTwo), DisplayNameProperty = "ColumnC", ValueProperty = "ColumnD")]
U
}
Когда у вас есть значение enum, вы проверяете словарь на наличие кэшированного метода, если он отсутствует, вы генерируете его.
Используя reflection, вы получаете информацию об этих свойствах, и, немного поднаторев в IL, это можно легко сделать.