|  12.06.2013, 19:12 | #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, напишите личное сообщение администратору. | 
|  | 
|  18.06.2013, 09:53 | #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). | |
|  18.06.2013, 10:41 | #3 | 
| Участник | Цитата: Наверно, имеется в виду то, что можно переделать методы-"фабрики" базовых классов таким образом, чтобы они использовали новую инфраструктуру SysExtension вместо явного прописывания всех наследников в своем коде. Правда, для этого надо каждому классу-наследнику повесить соотв. атрибут, но зато вызывающий код никак не изменится - он, условно, как передавал какой-нить енум в статический метод базового класса, так и будет передавать, только этот метод перестанет на этапе компиляции "знать", какой именно класс-наследник окажется создан для того или иного значения енума. Последний раз редактировалось gl00mie; 18.06.2013 в 10:53. Причина: добавление | 
|  | 
|  18.06.2013, 11:18 | #4 | 
| Участник | 
			
			Ну раньше можно было легко сделать такой финт - в конструкторе сделать вставку чтобы в зависимости от каких-то условий (например от параметров в настроечной табличке), сгенерить другого наследника. Поведение системы менялось, но мы не трогали кучу мест вызывающих конструктор. От пользователей класса это было скрыто. Как быть в данном случае теперь? Если у нас все однозначно определяется атрибутом, то получается что мы заданием атрибута жестко фиксируем конкретного наследника. Т.е. чтобы повторить вышеописанный финт, придется менять кучу мест коде ? Или теперь надо действовать как-то иначе ? Или внесение кастомизаций в Классфактори не запрещено, так что мы для переданного значения атрибута все же сможем подсунуть другого наследника ? Кстати, неявная связь - атрибут - наследник все равно есть. Перекрестные ссылки её позволяют отследить ? | 
|  | |
| За это сообщение автора поблагодарили: ta_and (3). | |
|  18.06.2013, 11:23 | #5 | 
| Участник | Цитата: кроме того, автор предполагает, что выбор зависит от одного параметра. а в реальном мире и в мире кастомизаций выбор подкласса зависит от кучи параметров. кроме того, далеко не очевидным способом. в общем, очередной архитектурный астронавт. решает совсем не ту проблему, которая есть на самом деле. причем дурацким способом. | 
|  | 
|  18.06.2013, 14:06 | #6 | 
| Участник | Цитата: 
		
			Сообщение от Logger
			   раньше можно было в зависимости от каких-то условий (например от параметров в настроечной табличке), сгенерить другого наследника. Как быть в данном случае теперь? Если у нас все однозначно определяется атрибутом, то получается что мы заданием атрибута жестко фиксируем конкретного наследника. Цитата: X++: if (trans.AccountNum == "ИП Пупкин") {...} else {...} Цитата: Цитата: Вопрос в том, как достичь этой ясности, но это во многом определяется архитектурными решениями, принимаемыми при разработке кастомизаций. Конечно, зачастую проще запрятать всю сложность хитросплетений разных факторов в один метод, иногда стандартное приложение подталкивает к тому, чтобы вместо, условно, нового типа журнала сделать "подтип", потому что существующий код в туче мест явно ссылается на определенные уже существующие типы журналов, полностью лишая возможности повторно использовать код за счет наследования. Но наивно было бы надеяться неряшливость своего и чужого кода выправить каким-либо красивым архитектурным решением. Цитата: 
 | 
|  | 
|  18.06.2013, 14:39 | #7 | 
| Участник | Цитата: 
		
			Сообщение от gl00mie
			   По-моему, это зависит от того, где располагается точка принятия решения: если клиентский код сам не знает, чего хочет, и решение отдано на откуп "умному" методу-фабрике, который неочевидным образом выбирает нужный подкласс, тогда да, указанный подход не работает, потому что фабрика SysExtension лишена искуственного интеллекта и знаний, специфичных для той или иной иерархии классов. Если же у клиентского кода есть ясность относительно того, что он хочет получить, то таких проблем не возникает. Гибкость теряется. Вся прелесть в том и была чтобы можно было подправив только конструктор, заставить кучу кода работать по-другому. См. пример с использованием семейства SysExcel и ComExcelDocument_RU и проблемами которые это повлекло, когда захотели везде в иерархии подменить использование этих классов на наследников работающих через .Net В такой новой схеме на ax2012 как бы ты реализовал эту задачу ? Может быть есть удобный и красивый вариант ? | 
|  | 
|  18.06.2013, 15:06 | #8 | 
| Участник | Цитата: Цитата: Т.е. вызывающий код не знает и не должен знать, с какой версией офиса он работает - это заморочки обертки (SysExcel, например). Но сама обертка знает, с какими версиями офиса она умеет работать, и знает это в куче мест, где по енуму MSOfficeVersion создается тот или иной класс-наследник. Если бы была задача научить ее работать с большим числом версий, то в 2012 это отчасти удобнее было бы делать с помощью новой "фабрики". | 
|  | |
| За это сообщение автора поблагодарили: Logger (2). | |
|  19.06.2013, 01:03 | #9 | 
| Banned | Цитата: 
		
			Сообщение от mazzy
			   ап-солютно согласен. кроме того, автор предполагает, что выбор зависит от одного параметра. а в реальном мире и в мире кастомизаций выбор подкласса зависит от кучи параметров. кроме того, далеко не очевидным способом. в общем, очередной архитектурный астронавт. решает совсем не ту проблему, которая есть на самом деле. причем дурацким способом. | 
|  | 
|  19.06.2013, 02:52 | #10 | 
| Участник | 
			
			перекрывать что-либо в текущем слое - типичный паттерн при кастомизации. не понимаю чем конструктор отличается. ну, перекрываем если так накастомизировали. и что? перекрестными ссылками ловится, с олд-слоем сравнивается. работаем по одному и тому же шаблону со всеми объектами. бесит как раз "уникальные подходы" в стиле: "сюда смотри, сюда не смотри, здесь рыбу заворачивали" | 
|  | |
| За это сообщение автора поблагодарили: Logger (2). | |
|  19.06.2013, 13:42 | #11 | 
| Участник | 
			
			SysExtension framework одно из средств чтобы было можно написать расширение для системы не меняя кода, а только добавляя его. Другие средства это, например, модели и события. Это позволяет, например, не мержить код при обновлении. Конечно, это подходит не для всех случаев, но множественность параметров, например, оно поддерживает. Мне кажется у части участников форума выработалась привычка к тем способам решения проблем, которые приняты в аксапте а в большой программистский мир они не смотрят. Я бы посоветовал почитать таким участникам про inversion of control и dependency injection так как это - явно следующий шаг. Последний раз редактировалось belugin; 19.06.2013 в 13:50. | 
|  | |
| За это сообщение автора поблагодарили: Logger (2). | |
|  19.06.2013, 14:05 | #12 | 
| Участник | Цитата: Тут я согласен - наверное, надо было пересадить на этот Фреймворк как можно больше подходящего кода - вон в source document + distributions свой примерно такой же, никак не связанный с этим | 
|  | 
|  19.06.2013, 14:27 | #13 | 
| Участник | 
			
			Хотелось бы еще получше понимать как теперь с помощью нового инструмента простым  способом  реализовать такое : Цитата: 
		
			Ну раньше можно было легко сделать такой финт - в конструкторе сделать вставку чтобы в зависимости от каких-то условий (например от параметров в настроечной табличке), сгенерить другого наследника. Поведение системы менялось, но мы не трогали кучу мест вызывающих конструктор. От пользователей класса это было скрыто.
		
	 | 
|  | 
|  19.06.2013, 14:55 | #14 | 
| Участник | 
			
			Описанная ситуация - это проектная заплатка, костылик для поддержки изменений, возникших уже после продумывания общей архитектуры и реализации решения. Очевидно, разработчики стандартного приложения (где теперь все не пишется, а сплошь моделируется, определяются шаблоны и т.п.) не станут предлагать механизм для облегчения прикручивания костыликов.
		 | 
|  | 
|  19.06.2013, 15:01 | #15 | 
| Участник | 
			
			Понятно.   Но ведь некоторые проекты внедрения и состоят сплошь из костылей, как какой-нить киношный терминатор убийца  Нельзя же в процессе внедрения поменять всю архитектуру. Приходится скакать в светлое будущее на костылях. А некоторые к инвалидной тележке моторчик привинтили. Хорошо катается   Последний раз редактировалось Logger; 19.06.2013 в 15:03. | 
|  | |
| За это сообщение автора поблагодарили: mazzy (2), fed (5), gl00mie (5). | |
|  19.06.2013, 15:51 | #16 | 
| Участник | Цитата: - во-вторых, можно закодировать условие в значение атрибута - в-третьих, посмотрите на ту надстройку, которая используется в templateprovider_ru - оно поддерживает иерархические атрибуты и условия | 
|  | |
| За это сообщение автора поблагодарили: Logger (3). | |
|  19.06.2013, 16:28 | #17 | 
| Участник | 
			
			Ок. Спасибо всем. Посмотрю рекомендованные описания. | 
|  | 
|  18.12.2014, 04:02 | #18 | 
| NavAx | Цитата: Вот в BankReconciliationMatchingMatchProcessor.constructMatch смысл ясен. Ребята игрались с toolbox, пробовали все, что под руку попалось. В результате получился конструктор для вызова конструктора, который вызывает фреймворк. 
				__________________ Isn't it nice when things just work? | 
|  | 
|  18.12.2014, 06:30 | #19 | 
| Участник | Цитата: Для того чтобы было легко, не меняя сами отчеты перекрыть для них это хранилище так и сделано. Вторая реализация есть, но она используется для тестирования внутри ms. | 
|  | 
|  18.12.2014, 07:05 | #20 | 
| NavAx | 
			
			А как переключение между наследниками происходит? Ну вот предположим захотел я использовать эту внутреннюю, ms-овскую, реализацию.
		 
				__________________ Isn't it nice when things just work? | 
|  | 
| Теги | 
| sysextension | 
|  | 
| 
 |