gifts2017

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

Опубликовал Юрий Осипов (yuraos) в раздел Программирование - Универсальные функции

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


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

Как известно, платформа 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…);
    
//…
КонецПроцедуры

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


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

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

В работе http://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 – демонстрационная обработка с примерами использования
(в том числе разные варианты выполнения в фоновом задании):

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

 

 

 

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
Пример.epf
.epf 12,19Kb
06.03.16
3
.epf 1.0 12,19Kb 3 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Юрий Осипов (yuraos) 16.12.13 23:02
Всем доброго времени суток!

В основе настоящей публикации, лежит изящный способ,
которым мне удалось исправить один недостаток в функционале
стандартных отчетов в УПП-1.2 еще под 1с-8.1.

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

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

...Показать Скрыть
2. Дмитрий Башинский (bashinsky) 17.12.13 09:40
Надо будет попробовать.
3. Яков Коган (Yashazz) 18.12.13 11:41
Просто и изящно. Статья, предваряющая решение, ценнее, т.к. эти очевидные вроде бы вещи изложены ясно, внятно, просто, лаконично. Спасибо!
rayastar; yuraos; +2 Ответить 1
4. DAnry (DAnry) 18.12.13 16:31
Очень интересно и познавательно. Благодарю за статью.
5. Юрий Осипов (yuraos) 18.12.13 16:57
(3) Yashazz, (4) DAnry,
спасибо за высокую оценку моих скромных трудов.
удивительное рядом ... но оно замутнено
(плохой документацией)

--
к стати описанный способ создания объекта не ограничивается обработками и отчетами.
например, как легко проверить в табло формул,
следующий оператор создает объект справочника "Контрагенты":
Новый(Тип(''СправочникОбъект.Контрагенты''))

хотя на практике я использовал это только для обработок и отчетов.
6. Яков Коган (Yashazz) 18.12.13 19:29
(5) Ну-у-у, в Синтакс-помощнике для "Новый" это всё описано, и ниразу не фишка, а вот придумать так воспользоваться этим способом для решения проблемы внеконтекстного вызова - фишка. Правда, позволю себе ламерский вопрос - разве при внеконтекстном вызове доступны значения реквизитов формы? У меня в своё время это не получалось.
7. Юрий Осипов (yuraos) 18.12.13 19:46
(6) Yashazz, нет реквизиты (то есть данные) формы
во внеконтекстных методах формы не доступны.

все что нужно для выполнения метода объекта
приходится передавать через аргументы вспомогательного метода формы
+ еще внутреннее текстовое представление типа объекта для создания самого объекта.
---
это может быть несколько занудно,
зато какая ни есть - оптимизация клиент-сервеного взаимодействия.
:)
8. Василий Зайцев (vasiliy_b) 20.12.13 14:43
9. Василий Казьмин (awk) 20.12.13 23:07
(0) Немного критики:

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

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

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

Общие модули конфигурации;
Модули менеджеров объектов;
Модули объектов;

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

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

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

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


Чушь какая-то. Я ни разу не менял модулей (общих) при написании внешних обработок. Они либо пишутся под конкретную конфигурацию, либо используют уж очень общие модули типа: "СтроковыеФункцииКлиентСервер". А вообще есть правило: "Хочешь потерять данные - сделай их внешними".

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

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

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

Процедура ПриСозданииНаСервере...
...
НоваяСтрока = ТаблицаСостояний.Добавить();
НоваяСтрока.Значение = Значение1;
НоваяСтрока.Представление = Представление1;
НоваяСтрока.Состояние1 = Истина;
НоваяСтрока.Состояние2 = Ложь;

...
КонецПроцедуры

&НаКлиенте
Процедура Что_тоПриИзменении(Элемент)

Строки = ТаблицаСостояний.НайтиСтроки(Новый Структура("Состояние1",Истина));
...

КонецПроцедуры


...Показать Скрыть
10. Юрий Осипов (yuraos) 20.12.13 23:34
(9) о тут у нас, появился Белинский и это хорошо!!!

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

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

Постараюсь позже высказать свои ответные соображения.
11. Юрий Осипов (yuraos) 22.12.13 18:24
(10)(9) ну awk,
выкладываю обещанные ответные соображения
...
так сказать, как у тебя - развернуто по пунктам.
12. Юрий Осипов (yuraos) 22.12.13 18:24
(11)***
(10)(9)

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


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

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

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


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

Мне не хотелось бы ввязываться в эту полемику, но скажу следующее:
Имеется одна (весьма похожая на 1С) программная среда - "Visual Basic for Applications" (VBA).
Она тоже оперирует с объектами своей предметной области (объектами приложений MS Office),
но там реализована полноценная поддержка классов и вроде бы это ничему не противоречит.
13. Юрий Осипов (yuraos) 22.12.13 18:25
(12)***
(10)(9)

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

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

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

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

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

Впрочем, спасибо за замечание.
Наверное, стоило об этом упомянуть в публикации - что я и сделаю в скором времени.
14. Юрий Осипов (yuraos) 22.12.13 18:25
(13)***
(10)(9)

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

Поспорить с утверждением трудно. Но по смыслу это замечание слабо связано с комментируемым в статье местом.
15. Юрий Осипов (yuraos) 22.12.13 18:26
(14)***
(10)(9)

Чушь какая-то. Я ни разу не менял модулей (общих) при написании внешних обработок. Они либо пишутся под конкретную конфигурацию,
либо используют уж очень общие модули типа: "СтроковыеФункцииКлиентСервер". А вообще есть правило: "Хочешь потерять данные -
сделай их внешними".

Снова интеллигентно не замечая слова "чушь", хочу сказать,
что замечание тоже не сильно уместно, так как отражает лишь личный опыт его автора.
Из того, что ему ни разу не приходилось чего-то делать, еще не следует, что это не актуально, или что этого не делают другие.

Впрочем, мысль, высказанная в конце замечания – безусловно, ценная!
16. Юрий Осипов (yuraos) 22.12.13 18:26
(15)***
(10)(9)

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

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

С моей точки зрения Модуль объекта, Модуль менеджера - это просто контейнеры кода, каждый со своим контекстом и способом доступа.
Их использование не ограничено только "оперированием данными".
В обычном приложении они часто используются для решения чисто интерфейсных задач:
- запрос подтверждения действий;
- вывода состояния выполнения;
- вывода предупреждений и сообщений;

Я думаю было бы полезно расширить абстракцию, заложенную в понятие "ОбщийМодуль", и ввести в конфигурацию
сущности нового типа, скажем, "ИсполняемыйМодуль", аналогичные объектам Module из MS VBA.
"ОбщиеМодули" были бы частным случаем объектов "ИсполняемыйМодуль", находящимися примерно
в том же соотношении, что объекты "ОбщаяФорма" и просто "Форма".

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

Подчиненные "ИсполняемыеМодули" могли бы помочь избежать потери функционала,
размещенного в модуле менеджера объекта, при сохранении отчетов и обработок
во внешних отчетах и обработках.

Доступ к подчиненным "ИсполняемымМодулям" на стороне клиентов управляемого приложения (и "вообще")
можно было бы, например, через новый атрибут "Модули" форм, объектов или менеджеров объектов:
// в контексте управляемой формы:
МодульСсылка = ЭтаФорма.Модули[ИмяМодуля]; 

// в контексте прикладного объекта:
МодульСсылка = ЭтотОбъект.Модули[ИмяМодуля]; 

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

...Показать Скрыть
17. Юрий Осипов (yuraos) 22.12.13 18:28
(16)
***
(10)(9)

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

Идея в принципе интересная ... так сказать, всё заготовить на сервере на все случаи жизни в форме.
В принципе я так и поступаю в некоторых случаях.
Например, в работе http://infostart.ru/public/236344/ есть два, фиксированных, часто используемых контекстных меню.
Списки значений этих меню сохраняются в реквизитах формы при создании на сервере.

НО ПРЕДЛАГАЕМЫЙ ПОДХОД - НЕ ЯВЛЯЕТСЯ ПАНАЦЕЕЙ:
Допустим число состояний, используемых в форме, велико, и допустим, что
при использовании формы вероятность реализации конкретного состояния мала;

Очевидно, что в этой ситуации такие "заготовки" - пустая трата ресурсов, как на стороне сервера, так и на стороне клиента.
Так же предлагаемый подход не идеален с точки зрения поддержки и "читаемости" кода.

PS:
- Вообще внеконтекстные вызовы сервера не считаются чем-то плохим, чего следует избегать.
- В принципе даже бытует мнение (с которым я не очень согласен), что какое-то "лишнее" число
серверных контекстных вызовов - меньшее зло, если их оптимизация "слишком" запутывает "читаемость" кода.
...
надо полагать из-за последнего обстоятельства в "управляемых" типовых конфигурациях визуально наблюдаются дикие тормоза.
18. Василий Казьмин (awk) 22.12.13 22:44
(12) yuraos, Начнем с главного. Бред и чушь - это попытка окрасить выражения эмоциями. Что достаточно сложно сделать посредством эпистолярного жанра. Так что это выражение моего непонимания, а не попытка задеть. Приятно иметь дело с человеком который это понимает. Если задел извини.

ООП и 1С.

Аналогия просто неуместна, по природе ООП. ООП - наследник процедурного, модульного программирования. Это все равно, что сравнивать отца и сына, при этом ставя в пример отцу сына.

Поспорить с утверждением трудно. Но по смыслу это замечание слабо связано с комментируемым в статье местом.
Это связано с приведенным в статье примером. Там у метода есть директива компиляции, причем ключевое слово "экспорт", почему-то опущено.

Из того, что ему ни разу не приходилось чего-то делать, еще не следует, что это не актуально, или что этого не делают другие.
Да. Мне не приходилось менять общие модули ради внешней обработки. Делать разные версии, под разные конфигурации - приходилось.


В обычном приложении они часто используются для решения чисто интерфейсных задач:
То-то и оно, что в обычном. Я не предрекаю его смерть (вполне хорошее и проверенное решение), но тенденции таковы, что 1С все дальше уходит в сторону распределенных вычислений, с явным выделением кода по местам его действия. Тут редко прокатывает (если прокатывает вообще): "Все на клиента, а там разберемся" или "Дернем сервер пару раз - гигабитка ведь у нас".

Я думаю было бы полезно расширить абстракцию, заложенную в понятие "ОбщийМодуль", и ввести в конфигурацию
сущности нового типа, скажем, "ИсполняемыйМодуль", аналогичные объектам Module из MS VBA.
"ОбщиеМодули" были бы частным случаем объектов "ИсполняемыйМодуль", находящимися примерно
в том же соотношении, что объекты "ОбщаяФорма" и просто "Форма"....
Для начала, неплохо было бы в 1С реализовать пространства имен и метаданные модулей, а не как сейчас (цитата из синтакс-помощника); "Неопределено - т.к. Не предполагается работа из встроенного языка"


Допустим число состояний, используемых в форме, велико, и допустим, что
при использовании формы вероятность реализации конкретного состояния мала;
В классическом веб программировании - это решается возможностью формы вкладывать в формы и асинхронными вызовами (AJAX), к сожалению это проигнорировано 1С. Так что остается три варианта:

1. Использовать разные формы
2. Передавать все необходимые данные на клиента
3. Дергать сервер.


При этом надо учесть, что 1С рекомендует сервак по пустякам не дергать.


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

Внеконтекстные вызовы сервера предназначены для уменьшения трафика при передачи данных от клиента на сервер. Только этим они отличаются от контекстных.

Пример 1: надо получить контрагента по документу основанию.

клиент сервер
1. форма выбора --> получение формы
2. При изменении <--
3. Получить контрагента --> ДокументОснование["Контрагент"]

В третьем шаге нет смысла тащить на сервер всю форму, со всеми реквизитами. Потому, целесообразно использовать НаСервереБезКонтекста.

В твоем варианте можно просто использовать:

Для методов модуля объекта:

&НаСервереБезКонтекста
Функция Что_то_с_чем_то(ОбъектОбработка, ТипОбработкиСтрока, Параметры)
Возврат ДанныеФормыВЗначение(ОбъектОбработка, Тип(ТипОбработкиСтрока)).НужнаяНамФункция(Параметры);
КонецФункции



Для методов модуля менеджера:

&НаСервереБезКонтекста
Функция Что_то_с_чем_то(Имя, Параметры)
Возврат Обработки[Имя].НужнаяНамФункция(Параметры);
КонецФункции
19. Елена Ситникова (lesenoklenok) 24.01.14 13:54
Спасибо за интересную статью
20. Степашка Никулин (Styvi) 03.10.14 17:28
всем спасибо, читал с интересом и статью и комменты, особенно СТАТЬЮ... спасибо АВТОРУ...
21. Александр Милютин (sanfoto) 29.06.15 16:06
Ндя прикольно разрабы платформы жгут.... ((((((
Дело в том, что у внешних обработок и отчетов нет менеджера объекта как такового.
А при сохранении встроенной обработки во внешнюю обработку модуль ее менеджера попросту теряется
(кстати, без предупреждения).


на днях случилось у меня это горе "при сохранении встроенной обработки во внешнюю обработку модуль ее менеджера попросту теряется"....

Работаем с "Хранилищем конфигурации", и тут другому программисту срочно понадобилась захваченная мною обработка для временной модификациив рабочей базе .... а мой код еще небыл доведен , ну я недолго думая сохранил в Файл как внешнюю обработку... отменил захват встроенной обработки.
Потом после работы "другого программиста" захватил обработку заново+загрузил свою сохраненую и прощай "мой модуль менеджера" (((((
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа