Оглавление
Обход элементов по шаблону проектирования Итератор
Постановка проблемы
Обход выборки из результата запроса по группировкам можно выполнить двумя способами: с итогами или без итогов. В первом случае необходимо в запросе указать поля группировки и итогов. Обход элементов выборки в этом случае осуществляется методом Следующий(). Во 2-м - достаточно получить линейный список и выполнить обход элементов выборки с помощью метода СледующийПоЗначениюПоля(). В обоих случаях обход элементов необходимо выполнять с использованием вложенных циклов, каждый уровень которых будет соответствовать обходу по одному полю группировки. Последнее обстоятельство может быть очень неудобным: приводит к громоздкому коду со вложенными циклами, значительно усложняет алгоритмы выборки, когда заранее неизвестен состав и порядок полей группировки.
Если же говорить о таблице значений, то для нее вообще не существует методов платформы, которые бы позволили выполнить обход её элементов по полям группировок. Однако существует способ свести задачу обхода из таблицы значений к обходу элементов выборки из результата запроса, использовав временную таблицу.
Шаблон проектирования Итератор решает проблему обхода элементов коллекции без использования методов самой коллекции. Удобство шаблона в том, что он предоставляет единый интерфейс обхода элементов без привязки к типу данных коллекции.
Согласно шаблону, Итератор предоставляет метод обхода Следующий(). Теперь представим, что у нас появилась возможность описать итератор для заданного типа коллекции: результат запроса, выборка из результата запроса, таблица, - тогда для выполнения обхода достаточно одного цикла с использованием метода итератора Следующий().
Использование шаблона Итератор значительно упрощает алгоритмы обхода элементов коллекций. Следующим шагом будет реализация такого итератора на языке 1С.
Поскольку 1С не поддерживает парадигму ООП, то реализация поведения Итератор будет заключаться в нахождении подходящей структуры данных и функций работы с найденной структурой.
Структура итератора:
-
ТекущиеДанные - ВыборкаИзРезультатаЗапроса, СтрокаТаблицыЗначений - структура для получения данных итератора
-
Источник - РезультатЗапроса, ВыборкаИзРезультатаЗапроса, Таблица
-
ПоляГруппировки - Массив - имена полей группировки
-
ИспользоватьИтоги - Булево - признак использования варианта обхода ПоГруппировкам для выборки из результата запроса
Основная функция работы с итератором: Следующий(СтруктураИтератора). Функция возвращает Истина, если Итератор спозиционировался на следующем элементе и Ложь - если предыдущее значение было последним.
В подсистему входит один общий модуль РаботаСИтератором. Модуль реализует функции
- ПолучитьСтруктуруИтератораВыборки
- СледующийИз*
Рисунок 1. Обработка стенд, реализующая различные алгоритмы обхода.
В поставке идет обработка, демонстрирующая различные алгоритмы выборки. Функции демонстрации вынесены в команды на основной форме.
Типичные алгоритмы с использованием итератора и без представлены на следующих листингах.
Листинг 1. Реализация обхода с использованием итератора
Листинг 2. Реализация обхода с использованием вложенных циклов
Рисунок 2. Сравнительный график времени выполнения различных алгоритмов обхода выборки из 2000 элементов, среднее время на 20 измерениях.
Реализация алгоритмов обхода выборки эквивалентна реализации через использование вложенных циклов. Дополнительные затраты связаны с проверками из-за универсальности реализации.
Обход таблицы оказался самым непроизводительным. Его можно оптимизировать, если в качестве источника использовать временную таблицу, однако тогда не будет возможности напрямую изменять данные.
В целом нельзя сказать, что производительность в данном случае фатально низкая. Многое зависит от условий задачи, размера выборки. У меня получилось, что обход с использованием итератора раз в 6-8 медленнее, чем через использование вложенных циклов. Анализ потерь производительности выявил, что потери сопоставимы с затратами на операторы проверки, чтения переменных и полей вспомогательной структуры (речь идет о микросекундах).
Идея оформить алгоритм обхода таблицы по группировкам вылилась в обобщенную идею обхода элементов выборки и элементов коллекций. При поиске решения использовалась идея шаблона проектирования Итератор.
На мой взгляд решение получилось красивое. Однако оно не безупречно, производительность решения по сравнению с классическим подходом оказалось меньше в несколько раз. Там где это возможно, решение использовать классический подход будет определяться в том числе и вопросом производительности. В тех же случаях, когда производительность не будет являться критическим фактором, решение вполне может себя оправдать за счет упрощения алгоритмов.
Принцип реализации шаблона проектирования Итератор на 1С универсален и его можно распространить и на другие алгоритмы обхода чего бы то ни было.