21.07.2019, 05:55 | #1 |
Участник
|
Паттерн initFrom() на таблице
Друзья, снова может быть ерундой занимаюсь, но все же прошу оценить. Суть паттерна в том, чтобы использовать один единственный метод для инициализации, остальные методы initFrom*() сделать private. С точки зрения пользователя кода это позволит сделать код немного чище и сосредоточиться на задаче не выискивая нужный метод в выпадающем списке. Сами делаем только на кастомных таблицах, используем весьма успешно.
X++: public void initFrom(Common _common) { switch (_common.TableId) { case tableNum(SalesLine): this.initFromSalesLine(_common); break; case tableNum(SalesTable): this.initFromSalesTable(_common); break; case tableNum(InventTable): this.initFromInventTable(_common); break; case tableNum(EcoResProduct): this.initFromEcoResProduct(_common); break; case tableNum(WMSBillOfLading): this.initFromWMSBillOfLading(_common); break; default: throw error(Error::wrongUseOfFunction(funcName())); } }
__________________
// no comments |
|
21.07.2019, 10:28 | #2 |
Участник
|
Цитата:
Будет сложнее использовать перекрестные ссылки, нельзя будет добавить доп. параметры в метод initFromSalesTable.., сложнее работать с кодом и отладчиком Особых плюсов я не очень вижу |
|
|
За это сообщение автора поблагодарили: Vadik (1), belugin (3), Logger (3), dech (2). |
21.07.2019, 20:10 | #3 |
Участник
|
|
|
|
За это сообщение автора поблагодарили: dech (2). |
22.07.2019, 12:35 | #4 |
Участник
|
Цитата:
Тогда код был бы гибче и возможно красивее. |
|
26.07.2019, 08:34 | #5 |
Участник
|
Красивее использовать
X++: myTable.initFrom(salesLine); X++: myTable.initFromSalesLine(salesLine); А вынос логики только ради этого, считаю, нецелесообразен. Да, согласен, надо контролировать, что уже есть в методе, чтобы не допустить ошибку Error::wrongUseOfFunction().
__________________
// no comments |
|
26.07.2019, 08:51 | #6 |
Участник
|
Это понятно вопрос в том что внутри initFrom
например там может быть жесткий switch как у вас а может быть вызов класса обработчика через конструктор где на основе атрибута (где например параметр tableName) собственно и выбирается конкретный обработчик. В этом случае вам в случае необходимости не надо лазить в табличку и менять в ней код достаточно просто добавлять класс обработчик с соответствующим атрибутом MyAttr(tableName(newTable)) для примера. |
|
26.07.2019, 09:11 | #7 |
Участник
|
Цитата:
В данном случае, любые, т.е. вообще любые аргументы "против" будут сходу отвергаться. Работает же. Чего вам еще надо-то? Тот факт, что это вообще-то, нарушает уже существующий стиль Axapta - не важно. Тот факт, что другие разработчики будут постоянно "спотыкаться" - не важно. Тот факт, что другие разработчики, скорее всего, создадут копию метода, но уже в привычном стиле initFromXXX - не важно. Тот факт, что метод сложно расширяемый с точки зрения параметров - не важно. И вообще, Best Practices придумали "враги" Я не вижу ни одной разумной причины так делать, кроме личных предпочтений. И что? Разве это все для Вас аргумент? Нет, конечно! Т.е. сам дискуссия смысла не имеет. Каждый останется при своем мнении
__________________
- Может, я как-то неправильно живу?! - Отчего же? Правильно. Только зря... Последний раз редактировалось Владимир Максимов; 26.07.2019 в 09:16. |
|
26.07.2019, 09:45 | #8 |
Участник
|
Да, перекрестные ссылки по функциям типа initFromSalesLine сразу придут в плохо воспринимаемый вид. Искать откуда это вызывается придётся дольше.
initFrom с switch-case хорош только в ситуациях когда на входе действительно появляется неизвестный common. Я с такими ситуациями не сталкивался. Наверное потому что не создаю их.
__________________
Дмитрий |
|
|
За это сообщение автора поблагодарили: dech (1). |
26.07.2019, 11:58 | #9 |
Участник
|
Цитата:
Сама по себе логика методов initFrom* понятна. Например, в таблице A есть внешний ключ на таблицу B, и нам этого не достаточно а нужно ещё помимо ссылки сохранить (для истории/для производительности/для гибкости) текущие значения каких-то ещё полей из таблицы B. В таком случае реализуя на таблице A метод initFromB мы создаём некоторую абстракцию, мы позволяем таблице А самой решать какие поля забрать из таблицы B. Если в дальнейшем понадобится изменить состав таких полей, то это можно будет сделать не меняя внешний код. Если у таблицы несколько внешних ключей, то получаем набор методов initFrom*. Но каждый из этих методов по логике должен вызываться строго в определённый момент, в момент инициализации соответствующего внешнего ключа. Мы же не рассматриваем ситуацию при которой на входе у нас кучка безликих курсоров, а на выходе мы должны получить целостную запись Единственное теоретическое применение обобщённого метода InitFrom, которое приходит в голову - это выполнение каких-то одинаковых действий при инициализации разных полей. Но что это может быть? Ваш паттерн явно и намеренно нарушает Принцип единственной ответственности (Single Responsibility Principle) - та самая S в известной аббревиатуре SOLID |
|
|
За это сообщение автора поблагодарили: dech (1). |
26.07.2019, 12:43 | #10 |
Участник
|
Цитата:
Можно кстати переписать шаблон на использование атрибутов и Plugin framework, тогда в нем гарантированно никто не разберется и он будет повышать job security |
|
|
За это сообщение автора поблагодарили: dech (1). |
26.07.2019, 12:54 | #11 |
Участник
|
В Аксапте нужны:
* перегрузка методов * генерики без этого лучше использовать традиционный способ |
|
|
За это сообщение автора поблагодарили: dech (1). |
|
|