Использование "точных" названий и разделенных классов
От:
Аноним
Дата:
01.09.08 14:44
Оценка:
Здравствуйте.
Есть несколько небольших проектов, которые разрабатывались как плагины к одному приложению. У меня появились несколько субъективных проблем
именование классов
использование раздельных классов (GUI и BL)
Почему субъективные — потому что для моего коллеги, вместе с которым мы делаем эту работу, это не видится проблемой.
Именование классов: в одном проекте у нас есть FilterEntity, в другом — ConditionEntity. Как-то это немного путает имхо, когда дальше в некой логике необходимо оперировать понятием ConditionEntity, который на самом деле FilterEntity. Да и слегка различаются наборы свойств (сейчас решено наследованием от FilterEntity). Сами по себе классы — просто контейнеры для данных.
Что касается разделения классов, то здесь я просто предлагал использовать разделение на GUI и BL. Сейчас диалоги работают напрямую с объектами, т.е. передаем диалогу ссылку на некий объект FilterEntity и диалог сам его изменяет, заполняет. Наверное, само по себе это уже не очень хорошо. Плюс, вышеназванная проблема именования — просто так теперь класс этого объекта не переименовать, т.к. все предыдущие проекты завязаны на старом названии.
Я бы сделал так: создал бы класс FilterEntityGui, который выставляет наружу только самые необходимые свойства для конкретного диалога FilterDialog. И работает данный конкретный диалог с этим классом. А все остальные пользователи этого диалога используют выходные данные по своему усмотрению.
Просто интересно, сталкивался ли кто с таким? Может, зря я паникую
Re: Использование "точных" названий и разделенных классов
Здравствуйте, Аноним, Вы писали:
А>Что касается разделения классов, то здесь я просто предлагал использовать разделение на GUI и BL. Сейчас диалоги работают напрямую с объектами, т.е. передаем диалогу ссылку на некий объект FilterEntity и диалог сам его изменяет, заполняет. Наверное, само по себе это уже не очень хорошо.
Само по себе это ни хорошо, ни плохо.
А>Плюс, вышеназванная проблема именования — просто так теперь класс этого объекта не переименовать, т.к. все предыдущие проекты завязаны на старом названии.
Значит, старые проекты тоже должны обновиться. Или "заморозиться".
А>Я бы сделал так: создал бы класс FilterEntityGui, который выставляет наружу только самые необходимые свойства для конкретного диалога FilterDialog. И работает данный конкретный диалог с этим классом. А все остальные пользователи этого диалога используют выходные данные по своему усмотрению.
Пока что маловато обоснований для прослойки. Зачем она? Если только для того, чтобы ограничить интерфейс Filter — то неправильно ставишь задачу. Прослойку имеет смысл делать только ради того, чтобы проще было решать какие-то задачи. Какие?
А>Просто интересно, сталкивался ли кто с таким? Может, зря я паникую
Да нет, вроде не зря. В именах, ИМХО, путаница получается.
Попробуйте для начала перепроектировать структуру классов, только выкиньте эти дурацкие приписки Entity — любой объект и так Entity. Получится, как минимум, Filter и Condition. Сразу вылезает интересное наблюдение: Filter включает в себя Condition и какое-то поведение по отношению к "фильтруемому" объекту. По крайней мере, с точки зрения семантики человеческого языка.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[2]: Использование "точных" названий и разделенных классов
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, Аноним, Вы писали:
А>>Что касается разделения классов, то здесь я просто предлагал использовать разделение на GUI и BL. Сейчас диалоги работают напрямую с объектами, т.е. передаем диалогу ссылку на некий объект FilterEntity и диалог сам его изменяет, заполняет. Наверное, само по себе это уже не очень хорошо. ГВ>Само по себе это ни хорошо, ни плохо.
Подумал, согласен.
А>>Плюс, вышеназванная проблема именования — просто так теперь класс этого объекта не переименовать, т.к. все предыдущие проекты завязаны на старом названии. ГВ>Значит, старые проекты тоже должны обновиться. Или "заморозиться".
Тоже вариант, но пока до заморозки рановато. Приходилось вносить незначительные изменения во все проекты. Есть шансы что еще придется.
А>>Я бы сделал так: создал бы класс FilterEntityGui, который выставляет наружу только самые необходимые свойства для конкретного диалога FilterDialog. И работает данный конкретный диалог с этим классом. А все остальные пользователи этого диалога используют выходные данные по своему усмотрению. ГВ>Пока что маловато обоснований для прослойки. Зачем она? Если только для того, чтобы ограничить интерфейс Filter — то неправильно ставишь задачу. Прослойку имеет смысл делать только ради того, чтобы проще было решать какие-то задачи. Какие?
Имхо, следующие задачи решать станет проще:
* реализация логики, связанной с фильтрами, если фильтры реализовать так, как удобно для бизнес-логики, а не для диалога.
* юнит-тестирование
Да, в первую очередь хотелось бы ограничить интерфейс Filter GUI. Как было в примере, в 3 разных проектах используется один и тот же диалог, но из-за того, что в нем используется класс сущности для извлечения данных, неудобно эту саму сущность изменять.
Попробую описать свою проблему конкретным примером
Структура проектов такая:
1. PluginProject1 (enum FilterTypes1)
2. PluginProject2 (enum FilterTypes2)
3. PluginCoreProject3 (BaseFilter, KeywordsFilterDialog, ListFilterDialog)
В PluginCoreProject3 есть классы фильтра BaseFilter и диалогов KeywordsFilterDialog, ListFilterDialog.
У фильтра BaseFilter есть поле Type — типа int.
public class BaseFilter
{
private int type;
public int Type {get; set;}
...
}
public class KeywordsFilterDialog : Form
{
public KeywordsFilterDialog(BaseFilter filter)
{
...
}
}
Проекты PluginProject1 и PluginProject2 используют BaseFilter, но Type трактуются в каждом по-своему. Для этого заведены enum'ы FilterTypes1 и FilterTypes2. В коде же используются преобразования типа:
Такие конструкции неудобны, когда дальше в логике приходится интенсивно использовать Filter.
Была идея сделать BaseFilter generic'ом, которому передавался бы свой enum в каждом проекте, но тут я уперся в диалоги. Диалоги в своих конструкторах обязательно принимают BaseFilter как один из аргументов. Неудобно конструктору GuiControl'а передавать generic тип. Использовать дизайнер форм становится сложнее.
Основной аргумент, против таких идей — не стоит вообще так заморачиваться для наших небольших проектов
А>>Просто интересно, сталкивался ли кто с таким? Может, зря я паникую ГВ>Да нет, вроде не зря. В именах, ИМХО, путаница получается.
ГВ>Попробуйте для начала перепроектировать структуру классов, только выкиньте эти дурацкие приписки Entity — любой объект и так Entity. Получится, как минимум, Filter и Condition. Сразу вылезает интересное наблюдение: Filter включает в себя Condition и какое-то поведение по отношению к "фильтруемому" объекту. По крайней мере, с точки зрения семантики человеческого языка.
Я тоже противник приписки Entity, но поскольку моему коллеге они удобны, я не настаиваю категорически.
Re[3]: Использование "точных" названий и разделенных классов
Здравствуйте, a.coder, Вы писали:
AC>Имхо, следующие задачи решать станет проще: AC>* реализация логики, связанной с фильтрами, если фильтры реализовать так, как удобно для бизнес-логики, а не для диалога. AC>* юнит-тестирование
Хорошо, допустим.
AC>Да, в первую очередь хотелось бы ограничить интерфейс Filter GUI. Как было в примере, в 3 разных проектах используется один и тот же диалог, но из-за того, что в нем используется класс сущности для извлечения данных, неудобно эту саму сущность изменять.
Да, вполне согласен. Такое вполне может статься, особенно, если сущность подкручивалась под нужды тех или иных диалогов.
AC>Попробую описать свою проблему конкретным примером
AC>Структура проектов такая: AC>1. PluginProject1 (enum FilterTypes1) AC>2. PluginProject2 (enum FilterTypes2) AC>3. PluginCoreProject3 (BaseFilter, KeywordsFilterDialog, ListFilterDialog)
AC>В PluginCoreProject3 есть классы фильтра BaseFilter и диалогов KeywordsFilterDialog, ListFilterDialog. AC>У фильтра BaseFilter есть поле Type — типа int.
.Net-овского reflection мало оказалось?
AC>
AC>public class BaseFilter
AC> ...
AC> public KeywordsFilterDialog(BaseFilter filter)
AC> ...
AC>
Странно. По идее KeywordsFilterDialog отлично знает о том, какой именно фильтр ему нужен (KeywordsFilter), но получает почему-то BaseFilter. Зачем такие сложности?
AC>Проекты PluginProject1 и PluginProject2 используют BaseFilter, но Type трактуются в каждом по-своему. Для этого заведены enum'ы FilterTypes1 и FilterTypes2. В коде же используются преобразования типа:
[skip преобразования]
AC>Такие конструкции неудобны, когда дальше в логике приходится интенсивно использовать Filter.
Ещё бы... Прости за ёрничество, а оперировать объектами нужных типов вместо базового религия не позволяет?
AC>Была идея сделать BaseFilter generic'ом, которому передавался бы свой enum в каждом проекте, но тут я уперся в диалоги.
Зачем??? Выкиньте вы этот хвост enum-ов. Не нужны они тут.
AC>Диалоги в своих конструкторах обязательно принимают BaseFilter как один из аргументов.
Ну вот и зачем? Зачем передавать в конструктор параметр базового типа, когда на самом деле нужен вполне определённый? Чтобы плодить код кастинга?
AC>Неудобно конструктору GuiControl'а передавать generic тип. Использовать дизайнер форм становится сложнее.
AC>Основной аргумент, против таких идей — не стоит вообще так заморачиваться для наших небольших проектов
Да нет, вопрос скорее в том, как обосновано решение о введении дополнительной прослойки. Если просто абстрактным "хорошо-плохо", то это одно, а если соображениями практического порядка — совсем другое. Но вам, ИМХО, имеет смысл поменять дизайн. Что-то больно много всего накручено, альтернативный способ идентификации типов через enum/int — вообще в топку (во всяком случае, из твоих примеров не следует, что это зачем-то нужно, кроме как для того, чтобы упражняться в преобразованиях BaseFilter).
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[4]: Использование "точных" названий и разделенных классов
От:
Аноним
Дата:
05.09.08 12:24
Оценка:
AC>>Структура проектов такая: AC>>1. PluginProject1 (enum FilterTypes1) AC>>2. PluginProject2 (enum FilterTypes2) AC>>3. PluginCoreProject3 (BaseFilter, KeywordsFilterDialog, ListFilterDialog)
AC>>В PluginCoreProject3 есть классы фильтра BaseFilter и диалогов KeywordsFilterDialog, ListFilterDialog. AC>>У фильтра BaseFilter есть поле Type — типа int.
ГВ>.Net-овского reflection мало оказалось?
Что-то не понимаю к чему это?
AC>>
AC>>public class BaseFilter
AC>> ...
AC>> public KeywordsFilterDialog(BaseFilter filter)
AC>> ...
AC>>
ГВ>Странно. По идее KeywordsFilterDialog отлично знает о том, какой именно фильтр ему нужен (KeywordsFilter), но получает почему-то BaseFilter. Зачем такие сложности?
Есть кусок кода, который создает эти диалоги и передает им фильтр. Этот кусок кода устроен так, что он не знает конкретных типов фильтра. Возможно, Вы и правы — тут что-то с дизайном.
AC>>Такие конструкции неудобны, когда дальше в логике приходится интенсивно использовать Filter. ГВ>Ещё бы... Прости за ёрничество, а оперировать объектами нужных типов вместо базового религия не позволяет?
Нет, религия тут ни при чем.
Тут дело в том, что у нас есть код, который просматривает коллекцию базовых фильтров. И в зависимости от типа фильтра делает какую-то работу. Как тут оперировать объектом нужного типа?
Например:
FiltersCollection collection = ...;
foreach (BaseFilter filter in collection)
{
switch ((FilterTypes)filter.Type)
{
case FilterTypes.FilterA:
[...]
case FilterTypes.FilterB:
[...]
}
}
AC>>Была идея сделать BaseFilter generic'ом, которому передавался бы свой enum в каждом проекте, но тут я уперся в диалоги. ГВ>Зачем??? Выкиньте вы этот хвост enum-ов. Не нужны они тут.
Мне нравится идея Только пока плохо себе представляю, как. Даже вопрос четко сформулировать пока не получается, что я хочу в итоге, если откажусь от enum-ов.
ГВ>Да нет, вопрос скорее в том, как обосновано решение о введении дополнительной прослойки. Если просто абстрактным "хорошо-плохо", то это одно, а если соображениями практического порядка — совсем другое. Но вам, ИМХО, имеет смысл поменять дизайн. Что-то больно много всего накручено, альтернативный способ идентификации типов через enum/int — вообще в топку (во всяком случае, из твоих примеров не следует, что это зачем-то нужно, кроме как для того, чтобы упражняться в преобразованиях BaseFilter).
Давно спорю с коллегой что тут что-то не так с дизайном. Многочисленные кастинги на самом деле раздражают, вот и думаю, как от них избавляться.
Re[5]: Использование "точных" названий и разделенных классов
Здравствуйте, Аноним, Вы писали:
AC>>>У фильтра BaseFilter есть поле Type — типа int. ГВ>>.Net-овского reflection мало оказалось? А>Что-то не понимаю к чему это?
Зачем дополнительно вводить Type типа int, когда у .Net полным-полно стандартных способов получить информацию о типе объекта? Больше того, по сути дела этот ваш Type — своего рода метаданные, а их вообще лучше всего заталкивать в атрибуты.
ГВ>>Странно. По идее KeywordsFilterDialog отлично знает о том, какой именно фильтр ему нужен (KeywordsFilter), но получает почему-то BaseFilter. Зачем такие сложности? А>Есть кусок кода, который создает эти диалоги и передает им фильтр. Этот кусок кода устроен так, что он не знает конкретных типов фильтра. Возможно, Вы и правы — тут что-то с дизайном.
Значит, этот кусок кода надо переписать. Что-то тут неправильно, если из-за одного куска кода в куче других кусков кода нужно писать массу дурных инструкций.
AC>>>Такие конструкции неудобны, когда дальше в логике приходится интенсивно использовать Filter. ГВ>>Ещё бы... Прости за ёрничество, а оперировать объектами нужных типов вместо базового религия не позволяет? А>Нет, религия тут ни при чем. А>Тут дело в том, что у нас есть код, который просматривает коллекцию базовых фильтров. И в зависимости от типа фильтра делает какую-то работу. Как тут оперировать объектом нужного типа?
Как правило, такой код свидетельствует об ошибках дизайна. А что будет, если добавится новый фильтр? Много таких кусков кода придётся дорабатывать? Здесь стоит подумать о том, чтобы вынести эту самую полезную работу непосредственно в фильтр. В общем, надо смотреть, что именно делают все эти куски кода и насколько часто такое встречается.
AC>>>Была идея сделать BaseFilter generic'ом, которому передавался бы свой enum в каждом проекте, но тут я уперся в диалоги. ГВ>>Зачем??? Выкиньте вы этот хвост enum-ов. Не нужны они тут. А>Мне нравится идея Только пока плохо себе представляю, как. Даже вопрос четко сформулировать пока не получается, что я хочу в итоге, если откажусь от enum-ов.
Скорее всего ты хочешь, чтобы можно было добавлять фильтры и диалоги фильтров, не слишком заморачиваясь доработками окружающих "кусков кода" и многочисленными кастингами.
А>Давно спорю с коллегой что тут что-то не так с дизайном. Многочисленные кастинги на самом деле раздражают, вот и думаю, как от них избавляться.
Перепроектированием. Иногда без кастингов не обойтись, но много-много чаще это означает, что попросту неправильно разложили функциональность по классам.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[6]: Использование "точных" названий и разделенных классов
[skip подробности]
А>>Давно спорю с коллегой что тут что-то не так с дизайном. Многочисленные кастинги на самом деле раздражают, вот и думаю, как от них избавляться. ГВ>Перепроектированием. Иногда без кастингов не обойтись, но много-много чаще это означает, что попросту неправильно разложили функциональность по классам.
Спасибо. Вы подтвердили мои сомнения по поводу дизайна. Будем решать с учетом Ваших рекомендаций.
Re[7]: Использование "точных" названий и разделенных классов
Здравствуйте, a.coder, Вы писали:
AC>Спасибо. Вы подтвердили мои сомнения по поводу дизайна. Будем решать с учетом Ваших рекомендаций.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re: Использование "точных" названий и разделенных классов