Внеконтекстный вызов методов объекта обработки (отчета) в управляемой форме

Описан способ внеконтекстного вызова методов объекта обработки (отчета) в управляемой форме для выполнения некоторых действий или возврата результатов каких-то вычислений, зависящих только от значений переданных методу параметров. Обсуждена применимость предлагаемого способа. Предлагаются способы обхода ограничений для случая запуска обработки в фоновом задании.

Сразу хочется отметить, что речь пойдет о повторном использовании методов, которые фактически являются «статическими» в терминологии ООП, то есть не связанных с конкретным экземпляром объекта. Такие методы, не изменяя состояния (данных) самого объекта, выполняют некоторые действия или (и) возвращают результаты каких-то вычислений.

Как известно, платформа 1С-8.2/8.3 предоставляет возможность повторного использования кода путем размещения его в экспортных процедурах и функциях в следующих местах конфигурации:

  1. Модули объектов «Форма» и «УправляемаяФорма»;
  2. Общие модули конфигурации;
  3. Модули менеджеров объектов;
  4. Модули объектов;

Рассмотрим подробней каждый из вариантов с точки зрения использования в управляемых формах в обработках или отчетах.

Модули объектов форм (по замечанию awk):

Этот вариант переиспользования не очень удобен по ряду причин:

— Объекты «Форма» или «УправляемаяФорма» отдельно создать можно только на стороне клиентов (метод ПолучитьФорму() не доступен на сервере). Поэтому на стороне сервера применение этого варианта переиспользования кода ограничено серверным контекстом управляемых форм.

— В силу узкой специализации объектов «Форма» или «УправляемаяФорма», призванных решать интерфейсные задачи.
На практике этот вариант переиспользования кода в основном используется для нестандартного начального заполнения данных формы до ее открытия или как один из возможных вариантов организации взаимодействия между между формами (в подчиненной форме через атрибут «ВладелецФормы» можно вызвать экспортный метод формы-владельца).

Общие модули конфигурации:

Этот вариант является самым простым с точки зрения использования на стороне клиента в управляемых формах, поскольку общие модули и их методы можно сделать непосредственно доступными для использования на клиенте:

&НаКлиенте
Процедура ОбработчикСобытия(Элемент…)
    
//…
    
ВычЗначение = ИмяОбщегоМодуля1.МетодФункция1(Пар1,Пар2,Пар3…);
    
//…
    
ИмяОбщегоМодуля2.МетодПроцедура2(Арг1,Арг2,Арг3…);
    
//…
КонецПроцедуры

Недостаток размещения кода в общих модулях заключается в уменьшении универсальности обработки (отчета).
Ее функционал «размазывается» по конфигурации. При переносе функционала в другое прикладное решение приходится помнить, что кроме самой обработки также требуется подтянуть «то, пятое, десятое».
А для универсальных обработок, используемых в качестве внешних, такая зависимость от общих модулей может оказаться вообще неприемлемой.

Модули менеджеров объектов:

Модуль менеджера объекта является естественным местом размещения кода общего назначения, не связанного с конкретным экземпляром объекта.

К сожалению, в нынешней реализации управляемого приложения модуль менеджера объекта не доступен на стороне клиента.
Поэтому вызов методов этого модуля приходится выполнять через вспомогательные серверные внеконтекстные методы формы:

&НаСервереБезКонтекста
Функция ФормМетодФункция1(Пар1,Пар2,Пар3…)
     Возврат
Обработки[ИмяОбработки]. МетодФункция1 (Пар1,Пар2,Пар3…);
КонецФункции

&НаСервереБезКонтекста
Процедура ФормМетодПроцедура2(Арг1,Арг2,Арг3…)
    
Обработки[ИмяОбработки]. МетодПроцедура2(Арг1,Арг2,Арг3…);
КонецПроцедуры

//…

&НаКлиенте
Процедура ОбработчикСобытия(Элемент…)
    
//…
    
ВычЗначение = ФормМетодФункция1(Пар1,Пар2,Пар3…);
    
//…
    
ФормМетодПроцедура2(Арг1,Арг2,Арг3…);
    
//…
КонецПроцедуры

В принципе такой вариант размещения кода является приемлемым для обработки с точки зрения производительности и переносимости. Но здесь возникает затруднение, если предполагается использовать обработку (отчет) в качестве внешней обработки (внешнего отчета).

Дело в том, что у внешних обработок и отчетов нет менеджера объекта как такового.
А при сохранении встроенной обработки во внешнюю обработку модуль ее менеджера попросту теряется (кстати, без предупреждения).
В этом случае остается единственное место для размещения повторно используемого кода – модуль объекта обработки (отчета).

Модули объектов:

Модуль объекта также не доступен на стороне клиента в управляемой форме.
Вызов методов объекта в общем случае возможен через вспомогательные серверные, но уже контекстные методы формы:

&НаСервере
Функция ФормМетодФункция1(Пар1,Пар2,Пар3…)
    
Обработка = РеквизитФормыВЗначение(«Объект»);
     Возврат
Обработка. МетодФункция1 (Пар1,Пар2,Пар3…);
КонецФункции

&НаСервере
Процедура ФормМетодПроцедура2(Арг1,Арг2,Арг3…)
    
Обработка = РеквизитФормыВЗначение(«Объект»);
    
Обработка. МетодПроцедура2(Арг1,Арг2,Арг3…);
КонецПроцедуры

//…

&НаКлиенте
Процедура ОбработчикСобытия(Элемент…)
    
//…
    
ВычЗначение = ФормМетодФункция1(Пар1,Пар2,Пар3…);
    
//…
    
ФормМетодПроцедура2(Арг1,Арг2,Арг3…);
    
//…
КонецПроцедуры

Серверные контекстные вызовы являются «затратными». Их использование оправдано, если в массовом порядке изменяются данные формы или когда для выполнения каких-то действий требуются данные всей формы или связанного с ней объекта.
Поэтому рекомендуется по возможности избегать использования серверных контекстных вызовов.

Что же делать, если метод объекта фактически является «статическим» и не использует данные самого объекта?

Например, пусть метод возвращает список значений меню, динамически зависящего только от значений переданных методу параметров. Ясно, что использование контекстного серверного вызова в этой ситуации явно неоправданно.

В работе //infostart.ru/public/236344/ при разработке управляемых форм обработки для решения этой проблемы был использован такой подход:

В специально предназначенном строковом реквизите обработки при инициализации модуля объекта сохраняется внутреннее строковое представление типа объекта обработки/отчета:

// установим внутреннее строковое представление типа значения объекта обработки
ЭтотОбъект.ОбработкаТип = ЗначениеВСтрокуВнутр(ТипЗнч(ЭтотОбъект));

Этот способ хорош тем, что «сразу» инициалициализирует нужный реквизит объекта обработки/отчета во всех формах, где объект обработки/отчета используется.

В принципе реквизит обработки можно заменить реквизитом самой формы.
Тогда описанное выше действие нужно будет выполнять в обработчике «ПриСозданииНаСервере»:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
Обработка = РеквизитФормыВЗначение(«Объект»);
    
// установим внутреннее строковое представление типа значения объекта обработки
    
ЭтаФорма.ОбработкаТип = ЗначениеВСтрокуВнутр(ТипЗнч(Обработка));

     //…

     ЗначениеВРеквизитФормы(Обработка, «Объект»);
КонецПроцедуры

Значение этого реквизита в дальнейшем используется во вспомогательных внеконтекстных серверных методах формы для создания объекта обработки. Ну, а сам вызов методов объекта обработки на стороне клиента выглядит следующим образом:

&НаСервереБезКонтекста
Функция ФормМетодФункция1(ОбработкаТип,Пар1,Пар2,Пар3)
   
// создаем объект обработки по внутреннему строковому представлению его типа
    // для внеконтекстного выполнения экспортных методов
   
Обработка = Новый (ЗначениеИзСтрокиВнутр(ОбработкаТип));
    Возврат
Обработка. МетодФункция1 (Пар1,Пар2,Пар3…);
КонецФункции

&НаСервереБезКонтекста
Процедура ФормМетодПроцедура2(ОбработкаТип,Арг1,Арг2,Арг3…)
   
// создаем объект обработки по внутреннему строковому представлению его типа
    // для внеконтекстного выполнения экспортных методов
   
Обработка = Новый (ЗначениеИзСтрокиВнутр(ОбработкаТип));
   
Обработка. МетодПроцедура2(Арг1,Арг2,Арг3…);
КонецПроцедуры

В 

//…

&НаКлиенте
Процедура ОбработчикСобытия(Элемент…)
    
//…
    
ВычЗначение = ФормМетодФункция1(Объект.ОбработкаТип,Пар1,Пар2,Пар3…);
    
//…
    
ФормМетодПроцедура2(Объект.ОбработкаТип,Арг1,Арг2,Арг3…);
    
//…
КонецПроцедуры
В 

Таким образом, решается поставленная задача:
вызовы методов объекта осуществляется при внеконтекстных серверных вызовах со стороны клиента в управляемой форме. 

Кроме этого описанный выше подход более универсален, чем использование модуля менеджера объекта.
Так как при таком создании объекта в явном виде не используется информация о том, что за объект создается (объект обработки, отчета или чего другого), а также информация об имени метаданных объекта.

Применение:

Описанный в данной публикации подход может оказаться полезным, если у разрабатывемого объекта планируется создание как управляемого, так и обычного интерфейса.

Ограничения применения:

В случае внешних отчетов и обработок предлагаемый подход можно использовать только в том соединении с информационной базой, в котором был открыт файл обработки/отчета (был откомпилирован модуль объекта из файла).

При использовании в другом соединении (например, в фоновом задании или во внешнем соединении) у нас не получится создать объект внешней обработки/отчета по переданному внутреннему строковому представлению типа объекта обработки/отчета (смотрите первый пример ниже по тексту).
Поскольку в этом случае функция ЗначениеИзСтрокиВнут() вернет значение Тип(“Неопределено”вместо типа нужного нам объекта.

Например, может возникнуть вполне естественное желание запустить на выполнение обработку в фоновом задании.
Для этого потребуется экспортный метод некоего общего модуля, позволяющего выполнять произвольный код на стороне сервера.
Пусть это будет общий модуль «УТР_Сервер» и метод «ВыполнитьНаСервере» (реальный пример из конфигурации «Управление аптечной сетью»):

Процедура ВыполнитьНаСервере(Строка, ПереданноеЗначение=Неопределено) Экспорт
    Выполнить(
Строка);
КонецПроцедуры

Запустить обработку на выполнение в фоновом задании с передачей типа объекта обработки для его создания можно попытаться так:

&НаСервереБезКонтекста
Функция ЗапуститьНаВыполнениеВФоновомЗаданииНаСервере1(ОбработкаТип,стАргументы,ТаймаутФЗ,ФоновоеЗаданиеКлюч,ЕррорИнфо)
   
Обработка = Новый(ЗначениеИзСтрокиВнутр(ОбработкаТип));
   
ОбработкаИмя = Обработка.Метаданные().Имя;

    стПараметры = Новый Структура(«А»,стАргументы);
   
стПараметры.Вставить(«ОбработкаТип»,ОбработкаТип);

    КодВыполнения =
   
«П = ПереданноеЗначение;
    |// по переданному типу объекта обработки — НЕ РАБОТАЕТ !!!
    |Обработка = Новый(ЗначениеИзСтрокиВнутр(П.ОбработкаТип));
    |Обработка.МетодПроцедура2(П.А.Арг1,П.А.Арг2,П.А.Арг3);
    |»
;

    ИмяМетодаФЗ = «УТР_Сервер.ВыполнитьНаСервере»;
   
ПараметрыФЗ = Новый Массив;
   
ПараметрыФЗ.Добавить(КодВыполнения); // исполняемый код, запускающий обработку на сервере
   
ПараметрыФЗ.Добавить(стПараметры); // параметры исполняемого кода

    ЕррорИнфо = «»;
    Попытка
       
Задание = ФоновыеЗадания.Выполнить(
       
ИмяМетодаФЗ,ПараметрыФЗ,ОбработкаИмя+«_»+ФоновоеЗаданиеКлюч,«Выполнение обработки «»»+ОбработкаИмя+«»»»);
        Если
ТаймаутФЗ > 0 Тогда
           
Задание.ОжидатьЗавершения(ТаймаутФЗ);
        КонецЕсли;
       
ЗаданиеGUID = Задание.УникальныйИдентификатор;;
    Исключение
       
ЗаданиеGUID = Неопределено;
       
ЕррорИнфо = ОписаниеОшибки();
    КонецПопытки;

    Возврат ЗаданиеGUID;
КонецФункции

Обход ограничений:

Что же делать, если очень хочется выполнить метод объекта внешней обработки/отчета именно в фоновом задании?
Тогда придется как-то передать фоновому заданию двоичные данные обработки (отчета) для создания ее (его) объекта.

Для этого есть три основных способа:

1) Передать через аргумент метода фонового задания навигационную ссылку на данные обработки/отчета в информационной базе
(для этого обработка должна быть сохранена в информационное базе,
например, в справочнике «ДополнительныеОтчетыИОбработки»):

&НаСервереБезКонтекста
Функция ПолучитьНавигационнуюСсылкуДопОбработки(ИмяОбработки)
   
УстановитьПривилегированныйРежим(Истина);
   
Запрос = Новый Запрос;
   
Запрос.Текст =
   
«ВЫБРАТЬ
    |   Т.Ссылка КАК Ссылка
    |ИЗ
    |   Справочник.ДополнительныеОтчетыИОбработки КАК Т
    |ГДЕ
    |   Т.ПометкаУдаления = ЛОЖЬ
    |   И Т.ИмяОбъекта = «»»
+ИмяОбработки+«»»
    |   И Т.Вид = ЗНАЧЕНИЕ(Перечисление.ВидыДополнительныхОтчетовИОбработок.ДополнительнаяОбработка)
    |   И Т.Публикация = ЗНАЧЕНИЕ(Перечисление.ВариантыПубликацииДополнительныхОтчетовИОбработок.Используется)»
;
   
Выборка = Запрос.Выполнить().Выбрать();
    Пока
Выборка.Количество() = 0 Цикл
        Возврат
«»;
    КонецЦикла;
   
Выборка.Следующий();
    Возврат
ПолучитьНавигационнуюСсылку(Выборка.Ссылка,«ХранилищеОбработки»);
КонецФункции

&НаСервереБезКонтекста
Функция ЗапуститьНаВыполнениеВФоновомЗаданииНаСервере2(ОбработкаТип,стАргументы,ТаймаутФЗ,ФоновоеЗаданиеКлюч,ЕррорИнфо)
   
Обработка = Новый(ЗначениеИзСтрокиВнутр(ОбработкаТип));
   
ОбработкаИмя = Обработка.Метаданные().Имя;

    стПараметры = Новый Структура(«А»,стАргументы);
   
стПараметры.Вставить(«ОбработкаАдрес»,ПолучитьНавигационнуюСсылкуДопОбработки(ОбработкаИмя));

    КодВыполнения =
   
«П = ПереданноеЗначение;
    |// по навигационной ссылке двоичных данных обработки в ИБ
    |Обработка = ВнешниеОбработки.Создать(ВнешниеОбработки.Подключить(П.ОбработкаАдрес,,Ложь));
    |Обработка.МетодПроцедура2(П.А.Арг1,П.А.Арг2,П.А.Арг3);
    |»
;

    ИмяМетодаФЗ = «УТР_Сервер.ВыполнитьНаСервере»;
   
ПараметрыФЗ = Новый Массив;
   
ПараметрыФЗ.Добавить(КодВыполнения); // исполняемый код, запускающий обработку на сервере
   
ПараметрыФЗ.Добавить(стПараметры); // параметры исполняемого кода

    ЕррорИнфо = «»;
    Попытка
       
Задание = ФоновыеЗадания.Выполнить(
       
ИмяМетодаФЗ,ПараметрыФЗ,ОбработкаИмя+«_»+ФоновоеЗаданиеКлюч,«Выполнение обработки «»»+ОбработкаИмя+«»»»);
        Если
ТаймаутФЗ > 0 Тогда
           
Задание.ОжидатьЗавершения(ТаймаутФЗ);
        КонецЕсли;
       
ЗаданиеGUID = Задание.УникальныйИдентификатор;;
    Исключение
       
ЗаданиеGUID = Неопределено;
       
ЕррорИнфо = ОписаниеОшибки();
    КонецПопытки;

    Возврат ЗаданиеGUID;
КонецФункции

2) Передать через аргумент метода фонового задания полный путь к файлу обработки/отчета
(полный путь можно получить из атрибута объекта “ИспользуемоеИмяФайла”,
этот путь должен быть доступен на стороне сервера):

&НаСервереБезКонтекста
Функция ЗапуститьНаВыполнениеВФоновомЗаданииНаСервере3(ОбработкаТип,стАргументы,ТаймаутФЗ,ФоновоеЗаданиеКлюч,ЕррорИнфо)
   
Обработка = Новый(ЗначениеИзСтрокиВнутр(ОбработкаТип));
   
ОбработкаИмя = Обработка.Метаданные().Имя;

    стПараметры = Новый Структура(«А»,стАргументы);
   
стПараметры.Вставить(«ОбработкаПутьФайла»,Обработка.ИспользуемоеИмяФайла);

    КодВыполнения =
   
«П = ПереданноеЗначение;
    |// по пути к файлу обработки
    |Обработка = ВнешниеОбработки.Создать(П.ОбработкаПутьФайла,Ложь);
    |Обработка.МетодПроцедура2(П.А.Арг1,П.А.Арг2,П.А.Арг3);
    |»
;

    ИмяМетодаФЗ = «УТР_Сервер.ВыполнитьНаСервере»;
   
ПараметрыФЗ = Новый Массив;
   
ПараметрыФЗ.Добавить(КодВыполнения); // исполняемый код, запускающий обработку на сервере
   
ПараметрыФЗ.Добавить(стПараметры); // параметры исполняемого кода

    ЕррорИнфо = «»;
    Попытка
       
Задание = ФоновыеЗадания.Выполнить(
       
ИмяМетодаФЗ,ПараметрыФЗ,ОбработкаИмя+«_»+ФоновоеЗаданиеКлюч,«Выполнение обработки «»»+ОбработкаИмя+«»»»);
        Если
ТаймаутФЗ > 0 Тогда
           
Задание.ОжидатьЗавершения(ТаймаутФЗ);
        КонецЕсли;
       
ЗаданиеGUID = Задание.УникальныйИдентификатор;;
    Исключение
       
ЗаданиеGUID = Неопределено;
       
ЕррорИнфо = ОписаниеОшибки();
    КонецПопытки;

    Возврат ЗаданиеGUID;
КонецФункции

В 

3) Передать через аргумент метода фонового задания сами двоичные данные файла обработки/отчета
(их можно получить конструктором по значению атрибута объекта “ИспользуемоеИмяФайла”):

&НаСервереБезКонтекста
Функция ЗапуститьНаВыполнениеВФоновомЗаданииНаСервере4(ОбработкаТип,стАргументы,ТаймаутФЗ,ФоновоеЗаданиеКлюч,ЕррорИнфо)
   
Обработка = Новый(ЗначениеИзСтрокиВнутр(ОбработкаТип));
   
ОбработкаИмя = Обработка.Метаданные().Имя;

    стПараметры = Новый Структура(«А»,стАргументы);
   
стПараметры.Вставить(«ОбработкаДанные»,Новый ДвоичныеДанные(Обработка.ИспользуемоеИмяФайла));

    КодВыполнения =
   
«П = ПереданноеЗначение;
    |// по двоичным данным обработки
    |ИмяФайла = ПолучитьИмяВременногоФайла(«».epf»»);
    |П.ОбработкаДанные.Записать(ИмяФайла);
    |Обработка = ВнешниеОбработки.Создать(ИмяФайла,Ложь);
    |Обработка.МетодПроцедура2(П.А.Арг1,П.А.Арг2,П.А.Арг3);
    |»
;

    ИмяМетодаФЗ = «УТР_Сервер.ВыполнитьНаСервере»;
   
ПараметрыФЗ = Новый Массив;
   
ПараметрыФЗ.Добавить(КодВыполнения); // исполняемый код, запускающий обработку на сервере
   
ПараметрыФЗ.Добавить(стПараметры); // параметры исполняемого кода

    ЕррорИнфо = «»;
    Попытка
       
Задание = ФоновыеЗадания.Выполнить(
       
ИмяМетодаФЗ,ПараметрыФЗ,ОбработкаИмя+«_»+ФоновоеЗаданиеКлюч,«Выполнение обработки «»»+ОбработкаИмя+«»»»);
        Если
ТаймаутФЗ > 0 Тогда
           
Задание.ОжидатьЗавершения(ТаймаутФЗ);
        КонецЕсли;
       
ЗаданиеGUID = Задание.УникальныйИдентификатор;;
    Исключение
       
ЗаданиеGUID = Неопределено;
       
ЕррорИнфо = ОписаниеОшибки();
    КонецПопытки;

    Возврат ЗаданиеGUID;
КонецФункции

В 

Описание файлов поставки:

Пример.epf – демонстрационная обработка с примерами использования
(в том числе разные варианты выполнения в фоновом задании):

 Форма обработки с примером использования

31 Comments

  1. yuraos

    Всем доброго времени суток!

    В основе настоящей публикации, лежит изящный способ,

    которым мне удалось исправить один недостаток в функционале

    стандартных отчетов в УПП-1.2 еще под 1с-8.1.

    Недостаток заключается в том, что внешний отчет нельзя открыть в новом окне.

    И исправляется этот недостаток буквально одной строчкой кода:

    // Открывает копию отчета в новом окне
    Процедура ОткрытьВНовомОкнеТиповойОтчет(ОтчетОбъект, ФормаОтчета) Экспорт
    
    НовыйОтчет = Новый (ТипЗнч(ОтчетОбъект)); // + yuraos
    //Если Строка(ОтчетОбъект) = «ВнешнийОтчетОбъект.» + ОтчетОбъект.Метаданные().Имя Тогда
    // Предупреждение(«Данный отчет является внешним.» + Символы.ПС + «Открытие нового отчета возможно только для объектов конфигурации.»);
    // Возврат;
    //Иначе
    // НовыйОтчет = Отчеты[ОтчетОбъект.Метаданные().Имя].Создать();
    //КонецЕсли;
    
    ЗаполнитьЗначенияСвойств(НовыйОтчет, ОтчетОбъект,, «СохраненнаяНастройка»);
    НовыйОтчет.КомпоновщикНастроек.ЗагрузитьНастройки(ОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки());
    ФормаНовогоОтчета = НовыйОтчет.ПолучитьФорму();
    НазначитьФормеУникальныйКлючИдентификации(ФормаНовогоОтчета);
    ФормаНовогоОтчета.ЭтоОтработкаРасшифровки = Истина;
    ФормаНовогоОтчета.Открыть();
    СформироватьТиповойОтчет(НовыйОтчет, ФормаНовогоОтчета.ЭлементыФормы.Результат, ФормаНовогоОтчета.ДанныеРасшифровки);
    ФормаНовогоОтчета.ЭтоОтработкаРасшифровки = Ложь;
    
    КонецПроцедуры
    
    

    Показать

    Reply
  2. bashinsky

    Надо будет попробовать.

    Reply
  3. Yashazz

    Просто и изящно. Статья, предваряющая решение, ценнее, т.к. эти очевидные вроде бы вещи изложены ясно, внятно, просто, лаконично. Спасибо!

    Reply
  4. DAnry

    Очень интересно и познавательно. Благодарю за статью.

    Reply
  5. yuraos

    (3) Yashazz, (4) DAnry,

    спасибо за высокую оценку моих скромных трудов.

    удивительное рядом … но оно замутнено

    (плохой документацией)





    к стати описанный способ создания объекта не ограничивается обработками и отчетами.

    например, как легко проверить в табло формул,

    следующий оператор создает объект справочника «Контрагенты»:

    Новый(Тип(»СправочникОбъект.Контрагенты»))
    

    хотя на практике я использовал это только для обработок и отчетов.

    Reply
  6. Yashazz

    (5) Ну-у-у, в Синтакс-помощнике для «Новый» это всё описано, и ниразу не фишка, а вот придумать так воспользоваться этим способом для решения проблемы внеконтекстного вызова — фишка. Правда, позволю себе ламерский вопрос — разве при внеконтекстном вызове доступны значения реквизитов формы? У меня в своё время это не получалось.

    Reply
  7. yuraos

    (6) Yashazz, нет реквизиты (то есть данные) формы

    во внеконтекстных методах формы не доступны.

    все что нужно для выполнения метода объекта

    приходится передавать через аргументы вспомогательного метода формы

    + еще внутреннее текстовое представление типа объекта для создания самого объекта.



    это может быть несколько занудно,

    зато какая ни есть — оптимизация клиент-сервеного взаимодействия.

    🙂

    Reply
  8. vasiliy_b

    Отличное решение.

    Reply
  9. awk
    Reply
  10. yuraos

    (9) о тут у нас, появился Белинский и это хорошо!!!

    Всегда полезна хорошая критика … если она умна, конструктивна и не предвзята.

    Спасибо, awk, за высказанные мысли по обсуждаемой теме

    и потраченное на это драгоценное время.

    Постараюсь позже высказать свои ответные соображения.

    Reply
  11. yuraos

    (10)(9) ну awk,

    выкладываю обещанные ответные соображения



    так сказать, как у тебя — развернуто по пунктам.

    Reply
  12. yuraos

    (11)***

    (10)(9)


    Бред. Т.к.:

    1. Статические методы вполне меняют данные (состояния), не объектов конечно, но классов.

    2. При чем 1С и ООП? 1С это процедурный язык оперирующий объектами предметной области.

    Интеллигентно не замечая слова «бред», спрашиваю себя К чему все это было сказано?

    И думаю, что к чему угодно, но только не к теме публикации.

    В начале статьи была использована аналогия с ООП, чтобы образно обрисовать область применения обсуждаемого

    в статье материала (и не более того). А именно, что обсуждаемый способ вызова методов объекта имеет смысл

    только для тех методов, которые не изменяют данные (или состояние объекта).

    Так как при возврате потока исполнения обратно на клиент все эти изменения будут утеряны.

    Причем аналогия осторожная: слово «статический» использовано в кавычках, а перед ним стоит слово «фактически».

    Скорее всего, это замечание связано с глухим неприятием ООП определенной частью сообщества 1С.

    Это неприятие породило давнюю, малоконструктивную дискуссию между сторонниками и противниками ООП в 1С.

    Мне не хотелось бы ввязываться в эту полемику, но скажу следующее:

    Имеется одна (весьма похожая на 1С) программная среда — «Visual Basic for Applications» (VBA).

    Она тоже оперирует с объектами своей предметной области (объектами приложений MS Office),

    но там реализована полноценная поддержка классов и вроде бы это ничему не противоречит.

    Reply
  13. yuraos

    (12)***

    (10)(9)


    А если метод будет в форме, то его нельзя использовать повторно?

    Умное замечание!

    Когда я писал статью, я был в раздумье: включить этот вариант переиспользования кода или нет.

    Но в последний момент передумал, так этот способ не очень удобен по ряду причин:

    — Объекты «Форма» или «УправляемаяФорма» отдельно создать можно только на стороне клиентов

    (метод ПолучитьФорму() не доступен на сервере). Поэтому на стороне сервера применение этого

    варианта переиспользования кода ограничено серверным контекстом управляемых форм.

    — В силу узкой специализации объектов «Форма» или «УправляемаяФорма», призванных решать интерфейсные задачи.

    На практике этот вариант переиспользования кода в основном используется для нестандартного начального

    заполнения данных формы до ее открытия или как один из возможных вариантов организации взаимодействия между

    между формами (в подчиненной форме через атрибут «ВладелецФормы» можно вызвать экспортный метод формы-владельца).

    Впрочем, спасибо за замечание.

    Наверное, стоило об этом упомянуть в публикации — что я и сделаю в скором времени.

    Reply
  14. yuraos

    (13)***

    (10)(9)


    Что-то я не встречал особо директив компиляции в общих модулях. Наверное потому, что хорошим тоном является разделение модулей на

    серверные и клиентские.

    Поспорить с утверждением трудно. Но по смыслу это замечание слабо связано с комментируемым в статье местом.

    Reply
  15. yuraos

    (14)***

    (10)(9)


    Чушь какая-то. Я ни разу не менял модулей (общих) при написании внешних обработок. Они либо пишутся под конкретную конфигурацию,

    либо используют уж очень общие модули типа: «СтроковыеФункцииКлиентСервер». А вообще есть правило: «Хочешь потерять данные —

    сделай их внешними».

    Снова интеллигентно не замечая слова «чушь», хочу сказать,

    что замечание тоже не сильно уместно, так как отражает лишь личный опыт его автора.

    Из того, что ему ни разу не приходилось чего-то делать, еще не следует, что это не актуально, или что этого не делают другие.

    Впрочем, мысль, высказанная в конце замечания – безусловно, ценная!

    Reply
  16. yuraos

    (15)***

    (10)(9)


    Модуль объекта, Модуль менеджера — это модули оперирования данными. На клиенте данные только отображаются, потому и нет их на

    клиенте. Максимум, что 1С могло бы сделать, это их доступность с неявным вызовом сервера. А оно надо? Если надо — вызови явно.

    Давать названия вещам надо осторожно.

    Проблема том, что названиям свойственно искажать внутреннюю сущность вещей. Неудачные названия порождают стереотипы и шаблоны.

    С моей точки зрения Модуль объекта, Модуль менеджера — это просто контейнеры кода, каждый со своим контекстом и способом доступа.

    Их использование не ограничено только «оперированием данными».

    В обычном приложении они часто используются для решения чисто интерфейсных задач:

    — запрос подтверждения действий;

    — вывода состояния выполнения;

    — вывода предупреждений и сообщений;

    Я думаю было бы полезно расширить абстракцию, заложенную в понятие «ОбщийМодуль», и ввести в конфигурацию

    сущности нового типа, скажем, «ИсполняемыйМодуль», аналогичные объектам Module из MS VBA.

    «ОбщиеМодули» были бы частным случаем объектов «ИсполняемыйМодуль», находящимися примерно

    в том же соотношении, что объекты «ОбщаяФорма» и просто «Форма».

    Такие пользовательские модули можно было бы подчинять другим объектам метаданных,

    локализуя тем самым специфическую функциональность в одном месте.

    Подчиненные «ИсполняемыеМодули» могли бы помочь избежать потери функционала,

    размещенного в модуле менеджера объекта, при сохранении отчетов и обработок

    во внешних отчетах и обработках.

    Доступ к подчиненным «ИсполняемымМодулям» на стороне клиентов управляемого приложения (и «вообще»)

    можно было бы, например, через новый атрибут «Модули» форм, объектов или менеджеров объектов:

    // в контексте управляемой формы:
    МодульСсылка = ЭтаФорма.Модули[ИмяМодуля];
    
    // в контексте прикладного объекта:
    МодульСсылка = ЭтотОбъект.Модули[ИмяМодуля];
    
    // в контекстах, где доступны менеджеры обработок:
    МодульСсылка = Обработки.БлокировкаСоединенийСИнформационнойБазой.Модули[ИмяМодуля];
    
    

    Показать

    Reply
  17. yuraos

    (16)

    ***

    (10)(9)


    А вызов сервера оправдан?

    Это легко решить передав таблицу состояний на клиента. А дальше не вызывая сервер:

    <…пример исполняемого кода…>

    Идея в принципе интересная … так сказать, всё заготовить на сервере на все случаи жизни в форме.

    В принципе я так и поступаю в некоторых случаях.

    Например, в работе http://infostart.ru/public/236344/ есть два, фиксированных, часто используемых контекстных меню.

    Списки значений этих меню сохраняются в реквизитах формы при создании на сервере.

    НО ПРЕДЛАГАЕМЫЙ ПОДХОД — НЕ ЯВЛЯЕТСЯ ПАНАЦЕЕЙ:

    Допустим число состояний, используемых в форме, велико, и допустим, что

    при использовании формы вероятность реализации конкретного состояния мала;

    Очевидно, что в этой ситуации такие «заготовки» — пустая трата ресурсов, как на стороне сервера, так и на стороне клиента.

    Так же предлагаемый подход не идеален с точки зрения поддержки и «читаемости» кода.

    PS:

    — Вообще внеконтекстные вызовы сервера не считаются чем-то плохим, чего следует избегать.

    — В принципе даже бытует мнение (с которым я не очень согласен), что какое-то «лишнее» число

    серверных контекстных вызовов — меньшее зло, если их оптимизация «слишком» запутывает «читаемость» кода.



    надо полагать из-за последнего обстоятельства в «управляемых» типовых конфигурациях визуально наблюдаются дикие тормоза.

    Reply
  18. awk
    Reply
  19. lesenoklenok

    Спасибо за интересную статью

    Reply
  20. Styvi

    всем спасибо, читал с интересом и статью и комменты, особенно СТАТЬЮ… спасибо АВТОРУ…

    Reply
  21. starik-2005

    (21) а вот даже интересно было бы посмотреть код обращения к модулю менеджера внешней обработки )))

    Reply
  22. yuraos

    (22) не в этой жизни и не на этой планете! 😉

    Reply
  23. yuraos

    (24) По хорошему эти изменения нужно было вносить в архитектуру платформы с появлением управляемого приложения (платформа версии 8.2).

    Но увы, что имеем — то имеем.

    Reply
  24. yuraos

    (21) ну что ж, sanfoto, сохраняй на всякий случай всю свою конфу.

    для отчетов — та же заподляна будет.

    Reply
  25. yuraos

    (27) temsan,

    под 8.3 не помню, наверное не пробывал,

    а под 8.2 мне не удавалось передавать данные формы в функцию на сервере без контекста

    ни в модуле формы, ни в серверный общий модуль с передачей на сервер.

    Наверное из-за того, что передавал их по ссылке.

    Платформа при этом выдавала мутную ошибку, что «нельзя изменять данные формы«,

    хотя я даже и не пытался переменной с данными формы что-либо присваивать.

    Reply
  26. temsan

    (28)

    Платформа при этом выдавала мутную ошибку, что «нельзя изменять данные формы»

    Для этого передаем параметр ОбъектОбработка по значению, но тогда не имеет смысл менять данные формы

    Функция Что_то_с_чем_то(Знач ОбъектОбработка, ТипОбработкиСтрока, Параметры)

    Оставим этот способ просто как вариант вызова методов модуля объекта, без контекстного вызова сервера.

    Reply
  27. bulpi

    Познавательно, плюс поставил, но практически для меня полезности ноль. Выдумывать хитрые велосипеды, когда можно поступить, как обычно, не стоит. Потом тебя будет материть тот, кто будет поддерживать после тебя. И ты сам себя через полгода.

    Reply
  28. SlavaKron

    Мы ведь знаем имя нашей внешней обработки, не проще ли вместо

    Обработка = Новый (ЗначениеИзСтрокиВнутр(ОбработкаТип))

    использовать

    Обработка = Новый («ВнешняяОбработкаОбъект.МояВнешняяОбработка»)

    Тогда и не придется создавать лишний реквизит формы и передавать его на сервер.

    Reply
  29. yuraos

    (31) Не всегда так можно обратиться к внешней обработке.

    Для этого она в соединении с базой должна быть «правильно подключена».

    Для обработки открываемой из внешнего файла, а не из справочника «Дополнительные бла-бла-бла«,

    это точно — не вариант.

    Reply
  30. SlavaKron

    (32) Почему вы так считаете? Я проверил оба варианта и в обоих работает.

    Reply
  31. yuraos

    (33) Ладно, работает.

    Но сути дела это тоже самое, только вместо самого типа объекта

    в операторе Новый используется строковое имя типа.

    Теперь пара ехидных вопроса:

    1. Что будет если вашу обработку встроить в конфигурацию?

    2. Что будет если ваш код перенести в обработку с другим именем

    или даже еще лучше в отчет ??

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *