AXForum  
Вернуться   AXForum > Блоги > dech
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск Все разделы прочитаны

Оценить эту запись

Изменяем паттерн 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-значения:
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()));
}
Итак, каждый раз, когда мы через menu item хотим запустить конкретный подкласс, мы должны следовать букве BP и создавать для каждого нового семейства свой Enum. Я пошел немного другим путём, который немного попроще, да и менее затратный по времени. Всё, что я опишу далее, касается только запуска классов через menu items. При вызове класса в коде лучше создавать свой статический метод construct(), хотя можно извратиться и создавать программно menu item и args. Но это уже перебор.
ОК, что нам нужно, чтобы упростить создание объектов? Интересный факт, свойство 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";
    }
}
После того, как классы сделаны, создаем 2 menu items для запуска суперкласса Base. Пусть один называется Base, а второй - Derived. Внимание, оба менюайтема вызывают один и тот же базовый класс. Для менюайтема Derived прописываем имя класса Derived в свойстве Parameters. для менюайтема Base можно ничего не прописывать, если имя класса совпадает с именем менюайтема.
А теперь тест! Запускаем Base, запускаем Derived. Инфолог выдаёт то, что мы и ожидаем. Поздравляю, мы с вами только что уделали Microsoft, который до сих пор указывает в BP использовать статический метод construct().
Однако, для AX2012 и выше этот код уже не актуален. Для запуска батчей теперь используется SysOperation Framework и атрибуты. Так что, если вы всё еще работаете в старой версии аксапты, прошу обкатывать новый паттерн.
Размещено в Без категории
Просмотров 32997 Комментарии 0
Всего комментариев 0

Комментарии

 


Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 20:52.