|
![]() |
#1 |
Участник
|
mfp: SysExtension Framework – to the rescue
Источник: http://blogs.msdn.com/b/mfp/archive/...he-rescue.aspx
============== There is a coding pattern that has been proliferating the X++ code base for years. It is not an X++ best practices – nor is it object oriented; yet it is used quite heavily (unfortunately). Consider a simple class hierarchy with an abstract base class and 3 derived classes. A typical implementation of a factory would be a static method on the base class, like this: (Please ignore the type of the parameter – it could be anything, I choose str for simplicity) ![]() Now; the problems with this approach are many.
SysExtension Framework to the rescue. Consider you decorate the subclasses with an attribute, like depicted here: ![]() Then you can rewrite the factory method to this: ![]() The extension framework returns an instance of the right subclass automatically. It uses the attribute to determine which subclass instance to create. Quite simple – extraordinary powerful! Now notice:
To learn more about the SysExtension framework see here. ============== Источник: http://blogs.msdn.com/b/mfp/archive/...he-rescue.aspx
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору. |
|
![]() |
#2 |
Участник
|
Интересная статья.
Но по-моему выгоды от предлагаемого подхода совсем неочевидны. Что сделал mfp ? Просто вынес код-создатель нужного наследника из конструктора в базовом классе в некий классфактори. По сути тоже самое. И ссылки из базового класса в наследники все равно по смыслу остались. Просто мы их на красивых схемах UML не увидим (од тех пор пока не нарисуем там еще и SysExtensionAppClassFactory ![]() Вместо ссылок из BaseClass к наследникам, мы увидим кучу ссылок из SysExtensionAppClassFactory к тем же наследникам. Сложность системы и число взаимных связей не уменьшилось ! Просто замели под половичок... А если предположить (судя по названию) что класс SysExtensionAppClassFactory будет использоваться не только для создания наследников BaseClass, но и других классов, то получится вообще катастрофа. Мы получили мегаконструктор, который содержит ссылки на кучу классов. Никакого упрощения не видно. Только красота отдельных кусков UML-схем. Цитата:
Truly decoupled! New subclasses can be added without any changes to the base class.
Цитата:
Less code is required! In the example here the delta is not significant – but sometimes you have switch statements spanning hundreds of lines.
Цитата:
No change in the public API! The contract stays the same – this is an easy and low risk refactoring.
|
|
|
За это сообщение автора поблагодарили: mazzy (2). |
![]() |
#3 |
Участник
|
Цитата:
Наверно, имеется в виду то, что можно переделать методы-"фабрики" базовых классов таким образом, чтобы они использовали новую инфраструктуру SysExtension вместо явного прописывания всех наследников в своем коде. Правда, для этого надо каждому классу-наследнику повесить соотв. атрибут, но зато вызывающий код никак не изменится - он, условно, как передавал какой-нить енум в статический метод базового класса, так и будет передавать, только этот метод перестанет на этапе компиляции "знать", какой именно класс-наследник окажется создан для того или иного значения енума. Последний раз редактировалось gl00mie; 18.06.2013 в 10:53. Причина: добавление |
|
![]() |
#4 |
Участник
|
Цитата:
кроме того, автор предполагает, что выбор зависит от одного параметра. а в реальном мире и в мире кастомизаций выбор подкласса зависит от кучи параметров. кроме того, далеко не очевидным способом. в общем, очередной архитектурный астронавт. решает совсем не ту проблему, которая есть на самом деле. причем дурацким способом. |
|
![]() |
#5 |
Участник
|
Цитата:
Сообщение от Logger
![]() раньше можно было в зависимости от каких-то условий (например от параметров в настроечной табличке), сгенерить другого наследника. Как быть в данном случае теперь? Если у нас все однозначно определяется атрибутом, то получается что мы заданием атрибута жестко фиксируем конкретного наследника.
Цитата:
X++: if (trans.AccountNum == "ИП Пупкин") {...} else {...} Цитата:
Цитата:
Вопрос в том, как достичь этой ясности, но это во многом определяется архитектурными решениями, принимаемыми при разработке кастомизаций. Конечно, зачастую проще запрятать всю сложность хитросплетений разных факторов в один метод, иногда стандартное приложение подталкивает к тому, чтобы вместо, условно, нового типа журнала сделать "подтип", потому что существующий код в туче мест явно ссылается на определенные уже существующие типы журналов, полностью лишая возможности повторно использовать код за счет наследования. Но наивно было бы надеяться неряшливость своего и чужого кода выправить каким-либо красивым архитектурным решением. Цитата:
|
|
![]() |
#6 |
Участник
|
Цитата:
Сообщение от gl00mie
![]() По-моему, это зависит от того, где располагается точка принятия решения: если клиентский код сам не знает, чего хочет, и решение отдано на откуп "умному" методу-фабрике, который неочевидным образом выбирает нужный подкласс, тогда да, указанный подход не работает, потому что фабрика SysExtension лишена искуственного интеллекта и знаний, специфичных для той или иной иерархии классов. Если же у клиентского кода есть ясность относительно того, что он хочет получить, то таких проблем не возникает.
Гибкость теряется. Вся прелесть в том и была чтобы можно было подправив только конструктор, заставить кучу кода работать по-другому. См. пример с использованием семейства SysExcel и ComExcelDocument_RU и проблемами которые это повлекло, когда захотели везде в иерархии подменить использование этих классов на наследников работающих через .Net В такой новой схеме на ax2012 как бы ты реализовал эту задачу ? Может быть есть удобный и красивый вариант ? |
|
![]() |
#7 |
Участник
|
Цитата:
Цитата:
Т.е. вызывающий код не знает и не должен знать, с какой версией офиса он работает - это заморочки обертки (SysExcel, например). Но сама обертка знает, с какими версиями офиса она умеет работать, и знает это в куче мест, где по енуму MSOfficeVersion создается тот или иной класс-наследник. Если бы была задача научить ее работать с большим числом версий, то в 2012 это отчасти удобнее было бы делать с помощью новой "фабрики". |
|
|
За это сообщение автора поблагодарили: Logger (2). |
![]() |
#8 |
Banned
|
Цитата:
Сообщение от mazzy
![]() ап-солютно согласен.
кроме того, автор предполагает, что выбор зависит от одного параметра. а в реальном мире и в мире кастомизаций выбор подкласса зависит от кучи параметров. кроме того, далеко не очевидным способом. в общем, очередной архитектурный астронавт. решает совсем не ту проблему, которая есть на самом деле. причем дурацким способом. |
|
![]() |
#9 |
Участник
|
Ну раньше можно было легко сделать такой финт - в конструкторе сделать вставку чтобы в зависимости от каких-то условий (например от параметров в настроечной табличке), сгенерить другого наследника. Поведение системы менялось, но мы не трогали кучу мест вызывающих конструктор. От пользователей класса это было скрыто.
Как быть в данном случае теперь? Если у нас все однозначно определяется атрибутом, то получается что мы заданием атрибута жестко фиксируем конкретного наследника. Т.е. чтобы повторить вышеописанный финт, придется менять кучу мест коде ? Или теперь надо действовать как-то иначе ? Или внесение кастомизаций в Классфактори не запрещено, так что мы для переданного значения атрибута все же сможем подсунуть другого наследника ? Кстати, неявная связь - атрибут - наследник все равно есть. Перекрестные ссылки её позволяют отследить ? |
|
|
За это сообщение автора поблагодарили: ta_and (3). |
![]() |
#10 |
Участник
|
перекрывать что-либо в текущем слое - типичный паттерн при кастомизации.
не понимаю чем конструктор отличается. ну, перекрываем если так накастомизировали. и что? перекрестными ссылками ловится, с олд-слоем сравнивается. работаем по одному и тому же шаблону со всеми объектами. бесит как раз "уникальные подходы" в стиле: "сюда смотри, сюда не смотри, здесь рыбу заворачивали" |
|
|
За это сообщение автора поблагодарили: Logger (2). |
![]() |
#11 |
Участник
|
Цитата:
Тут я согласен - наверное, надо было пересадить на этот Фреймворк как можно больше подходящего кода - вон в source document + distributions свой примерно такой же, никак не связанный с этим |
|
![]() |
#12 |
Участник
|
SysExtension framework одно из средств чтобы было можно написать расширение для системы не меняя кода, а только добавляя его. Другие средства это, например, модели и события.
Это позволяет, например, не мержить код при обновлении. Конечно, это подходит не для всех случаев, но множественность параметров, например, оно поддерживает. Мне кажется у части участников форума выработалась привычка к тем способам решения проблем, которые приняты в аксапте а в большой программистский мир они не смотрят. Я бы посоветовал почитать таким участникам про inversion of control и dependency injection так как это - явно следующий шаг. Последний раз редактировалось belugin; 19.06.2013 в 13:50. |
|
|
За это сообщение автора поблагодарили: Logger (2). |
![]() |
#13 |
Участник
|
Хотелось бы еще получше понимать как теперь с помощью нового инструмента простым способом
реализовать такое : Цитата:
Ну раньше можно было легко сделать такой финт - в конструкторе сделать вставку чтобы в зависимости от каких-то условий (например от параметров в настроечной табличке), сгенерить другого наследника. Поведение системы менялось, но мы не трогали кучу мест вызывающих конструктор. От пользователей класса это было скрыто.
|
|
![]() |
#14 |
Участник
|
Описанная ситуация - это проектная заплатка, костылик для поддержки изменений, возникших уже после продумывания общей архитектуры и реализации решения. Очевидно, разработчики стандартного приложения (где теперь все не пишется, а сплошь моделируется, определяются шаблоны и т.п.) не станут предлагать механизм для облегчения прикручивания костыликов.
|
|
![]() |
#15 |
Участник
|
Цитата:
- во-вторых, можно закодировать условие в значение атрибута - в-третьих, посмотрите на ту надстройку, которая используется в templateprovider_ru - оно поддерживает иерархические атрибуты и условия |
|
|
За это сообщение автора поблагодарили: Logger (3). |
![]() |
#16 |
NavAx
|
Цитата:
Вот в BankReconciliationMatchingMatchProcessor.constructMatch смысл ясен. Ребята игрались с toolbox, пробовали все, что под руку попалось. В результате получился конструктор для вызова конструктора, который вызывает фреймворк.
__________________
Isn't it nice when things just work? |
|
![]() |
#17 |
Участник
|
Цитата:
Для того чтобы было легко, не меняя сами отчеты перекрыть для них это хранилище так и сделано. Вторая реализация есть, но она используется для тестирования внутри ms. |
|
![]() |
#18 |
NavAx
|
А как переключение между наследниками происходит? Ну вот предположим захотел я использовать эту внутреннюю, ms-овскую, реализацию.
__________________
Isn't it nice when things just work? |
|
![]() |
#19 |
Участник
|
Понятно.
![]() Но ведь некоторые проекты внедрения и состоят сплошь из костылей, как какой-нить киношный терминатор убийца ![]() Нельзя же в процессе внедрения поменять всю архитектуру. Приходится скакать в светлое будущее на костылях. А некоторые к инвалидной тележке моторчик привинтили. Хорошо катается ![]() Последний раз редактировалось Logger; 19.06.2013 в 15:03. |
|
|
За это сообщение автора поблагодарили: mazzy (2), fed (5), gl00mie (5). |
![]() |
#20 |
Участник
|
Ок.
Спасибо всем. Посмотрю рекомендованные описания. |
|
Теги |
sysextension |
|
Опции темы | Поиск в этой теме |
Опции просмотра | |
|