Изменяем паттерн construct()
Запись от dech размещена 19.03.2018 в 15:45
Давайте посмотрим, что нам говорит Best Practices. Используйте метод construct() в каждом классе, чтобы можно было его правильно расширять классами-потомками и вызывать через menu items. Что касается таких классов как SalesLineType - говорить нечего. Метод construct() используется чисто как шаблон проектирования Строитель/Builder. Однако, разработчики решили, что этого мало, и стали использовать Enum для запуска конкретного подкласса из какого-либо семейства классов, например SalesFormLetter. Заполняем в menu item свойства EnumTypeParameter и EnumParameter, запускаем его и через Args наш класс получает нужное значение enum. Далее - дело техники, метод construct() создает нужный экземпляр на основе переданного enum-значения: Итак, каждый раз, когда мы через menu item хотим запустить конкретный подкласс, мы должны следовать букве BP и создавать для каждого нового семейства свой Enum. Я пошел немного другим путём, который немного попроще, да и менее затратный по времени. Всё, что я опишу далее, касается только запуска классов через menu items. При вызове класса в коде лучше создавать свой статический метод construct(), хотя можно извратиться и создавать программно menu item и args. Но это уже перебор.
ОК, что нам нужно, чтобы упростить создание объектов? Интересный факт, свойство Parameters типа строка используется реже, чем EnumParameter. Я решил через него передавать имя класса для создания нового объекта. Это даст возможность передавать еще и enum для каких-либо дополнительных целей. Я перенёс метод construct() в класс Global, сделав его по существу глобальной функцией. Чтобы он заработал как надо, я добавил следующий код:
Кто использует метки, создайте метку для последнего сообщения.
Далее, для проверки можно создать пару классов, пусть они называются Base и Derived:
После того, как классы сделаны, создаем 2 menu items для запуска суперкласса Base. Пусть один называется Base, а второй - Derived. Внимание, оба менюайтема вызывают один и тот же базовый класс. Для менюайтема Derived прописываем имя класса Derived в свойстве Parameters. для менюайтема Base можно ничего не прописывать, если имя класса совпадает с именем менюайтема.
А теперь тест! Запускаем Base, запускаем Derived. Инфолог выдаёт то, что мы и ожидаем. Поздравляю, мы с вами только что уделали Microsoft, который до сих пор указывает в BP использовать статический метод construct().
Однако, для AX2012 и выше этот код уже не актуален. Для запуска батчей теперь используется SysOperation Framework и атрибуты. Так что, если вы всё еще работаете в старой версии аксапты, прошу обкатывать новый паттерн.
X++:
static SalesFormLetter construct(DocumentStatus document, boolean getParmId = true) { switch(document) { case DocumentStatus::Confirmation : return new SalesFormLetter_Confirm (getParmId); case DocumentStatus::PickingList : return SalesFormLetter_PickingList::construct(getParmId); case DocumentStatus::PackingSlip : return new SalesFormLetter_PackingSlip (getParmId); case DocumentStatus::ProjectPackingSlip : return new SalesFormLetter_PackingSlipProject(getParmId); case DocumentStatus::Invoice : return new SalesFormLetter_Invoice (getParmId); case DocumentStatus::ProjectInvoice : return new SalesFormLetter_InvoiceProject (getParmId); default : throw error(strfmt("@SYS19306",funcname())); } throw error(strfmt("@SYS19306",funcname())); }
ОК, что нам нужно, чтобы упростить создание объектов? Интересный факт, свойство Parameters типа строка используется реже, чем EnumParameter. Я решил через него передавать имя класса для создания нового объекта. Это даст возможность передавать еще и enum для каких-либо дополнительных целей. Я перенёс метод construct() в класс Global, сделав его по существу глобальной функцией. Чтобы он заработал как надо, я добавил следующий код:
X++:
public static Object construct(Args _args) { DictClass dictClass; IdentifierName className; ; if (!_args) throw error(Error::missingParameter(null)); className = _args.parm() ? _args.parm() : _args.menuItemName(); dictClass = new DictClass(classname2id(className)); if (!dictClass) throw error(strfmt("Unable to instantiate \"%1\" class", className)); return dictClass.makeObject(); }
Далее, для проверки можно создать пару классов, пусть они называются Base и Derived:
X++:
class Base { public static void main(Args _args) { Base base = construct(_args); ; info(base.getType()); } public ClassDescription getType() { return "Base"; } }
X++:
class Derived extends Base { public ClassDescription getType() { return "Derived"; } }
А теперь тест! Запускаем Base, запускаем Derived. Инфолог выдаёт то, что мы и ожидаем. Поздравляю, мы с вами только что уделали Microsoft, который до сих пор указывает в BP использовать статический метод construct().
Однако, для AX2012 и выше этот код уже не актуален. Для запуска батчей теперь используется SysOperation Framework и атрибуты. Так что, если вы всё еще работаете в старой версии аксапты, прошу обкатывать новый паттерн.
Всего комментариев 0