Принципы ООП в 1С на примере реализации pattern Decorator

21.06.18

Разработка - Рефакторинг и качество кода

В данной статье будет рассмотрен пример реализации GoF паттерна проектирования decorator в среде разработки 1С. Основная цель данного шаблона, это возможность динамического расширения функциональности базового класса. Сразу оговорюсь, т.к. в 1С нет ООП, это будет не чистый пример реализации данного шаблона, однако свою задачу данный пример будет решать.

Файлы

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование Скачано Купить файл
Принципы ООП в 1С на примере реализации pattern Decorator:
.zip 12,71Kb
5 2 500 руб. Купить

Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний

Оформите подписку на компанию для решения рабочих задач

Оформить подписку и скачать решение со скидкой

Вы можете заказать платную доработку или адаптацию этой разработки под вашу конфигурацию на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

 

Для начала ознакомимся с UML диаграммой шаблона decorator

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

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

 

Приступим к реализации. 

Например, перед нами стоит задача реализовать алгоритм поиска контрагента.

создаем обработку с экспортным методом в модуле объекта НайтиКонтрагента(ИНН, КПП); вызов из кода будет такой

Объект = Обработки.ПоискКонтрагента.Создать();
Контрагент = Объект.НайтиКонтрагента(ИНН, КПП); // Какой-то ИНН и какой-то КПП

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

 

Давайте подумаем, какую роль выполняет интерфейс в ООП? Как нам подсказывает вики 

устанавливают взаимные обязательства между элементами программной системы

Если своими словами, то объявленные методы в интерфейсе обязательно должны быть реализованы в каждом классе который реализует этот интерфейс.

Для реализации интерфейса создаем новую обработку "ПоискКонтрагентаИнтерфейс". Содержащая реквизит РеализующийОбъект, тип ОбработкаОбъект.ПоискКонтрагента (или составной, для случаев если данный интерфейс имплементируют несколько классов)

Содержимое модуля объекта

 

Метод Имплементация - основной, он делает проверку на существования в реализующем классе необходимых методов (правда коряво эта проверка происходит), так же инициализирует значением реквизит РеализующийОбъект.

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


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

Функция Имплементация(ИнтерфейсИмя) Экспорт 
	Возврат Обработки[ИнтерфейсИмя].Создать().Имплементация(ЭтотОбъект);
КонецФункции

и Наследовать() 

Функция Наследовать(БазовыйОбъект) Экспорт 
	ЭтотОбъект.БазовыйОбъект = БазовыйОбъект;	
	Возврат ЭтотОбъект;
КонецФункции

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

В начале метода НайтиКонтрагента делаем проверку

Если ДанныеВерсии.Свойство("РежимПроверки") И ДанныеВерсии.РежимПроверки Тогда
  Возврат Неопределено;	
КонецЕсли;

Это нужно для метода ПроверитьСуществованиеМетодов (который у нас в модуле Интерфейсы). Ну нет у 1С нормального способа проверить существует ли метод в модуле объекта или нет.


Вот так изменится вызов метода НайтиКонтрагента

Данные = Новый Структура("ИНН, КПП", КакойтоИНН, КакойтоКПП); // Входящий параметр теперь один, структура.
Интерфейс = Обработки.ПоискКонтрагента.Создать().Имплементация("ПоискКонтрагентаИнтерфейс"); // ПоискКонтрагентаИнтерфейс - имя обработки интерфейса.
Контрагент = Интерфейс.НайтиКонтрагента(Данные); // Вызов через интерфейс


 

Зачем такие сложности скажите вы, зато теперь мой "интерфейс" могут имплементировать разные обработки разной структуры и разными методами, но мы 100% уверены, что у любой обработки есть нужный нам метод и мы можем вызвать его используя интерфейс.

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


Теперь реализуем сам декоратор.

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

Для этого создаем еще один класс обработку Декоратор1, копия обработки ПоискКонтрагента 

Единственное изменение, это доработанный метод НайтиКонтрагента(), доработан он таким образом:

Функция НайтиКонтрагента(Данные) Экспорт 
	Если ДанныеВерсии.Свойство("РежимПроверки") И ДанныеВерсии.РежимПроверки Тогда
		Возврат Неопределено;	
	КонецЕсли;

	Версия = БазовыйОбъект.НайтиКонтрагента(Данные); // Вызываем поиск базового объекта.
// Дополнение которое привносит декоратор.
	Если Не ЗначениеЗаполнено(Версия) Тогда
		Версия = СоздатьКонтрагента(ДанныеВерсии);	
	КонецЕсли;
	
	Возврат Версия;
КонецФункции
Функция СоздатьКонтрагента(ДанныеВерсии)
	// Создаем.	
	Сообщить("Создаем новый элемент справочника"); // Для демонстрации, что вызов есть.
КонецФункции

Тип реквизита БазовыйОбъект составной, по сути все типы от которых может наследоваться этот класс, а именно ПоискКонтрагента, ПоискКонтрагентаИнтерфейс. Данный класс так же реализует интерфейс ПоискСправочникаИнтерфейс, по этому у его реквизита РеализующийОбъект нужно сделать так же составной тип в который входит новый класс. Кстати это удобней делать через определяемые типы. 

Вызов будет таким:

Данные = Новый Структура("ИНН, КПП", КакойтоИНН, КакойтоКПП); // Входящий параметр теперь один, структура.
Интерфейс = Обработки.ПоискСправочника.Создать().Имплементация("ПоискСправочникаИнтерфейс");
Декоратор1 = Обработки.Декоратор1.Создать()
								.Наследовать(Интерфейс)
								.Имплементация("ПоискСправочникаИнтерфейс");
Контрагент = Декоратор1.НайтиКонтрагента(Данные);

Обращаю внимание, что декоратор наследуется от интерфейса и новый объект так же имплементирует ПоискКонтрагентаИнтерфейс

Если мы захотим еще обернуть, то просто создаем копию декоратора 1 и реализуем в нем свои изменения, в моем примере это вывод еще одного сообщения (не забываем про типы реквизитов БазовыйОбъект и РеализующийОбъект)

Функция СоздатьКонтрагента(ДанныеВерсии)
	Сообщить("Что-то делаем"); // Для демонстрации, что вызов есть.
КонецФункции

Вызов изменится так: 

Данные = Новый Структура("ИНН, КПП", КакойтоИНН, КакойтоКПП); // Входящий параметр теперь один, структура.
Интерфейс = Обработки.ПоискСправочника.Создать().Имплементация("ПоискСправочникаИнтерфейс");
Декоратор1 = Обработки.Декоратор1.Создать()
								.Наследовать(Интерфейс)
								.Имплементация("ПоискСправочникаИнтерфейс");

Декоратор2 = Обработки.Декоратор2.Создать()
								.Наследовать(Декоратор1)
								.Имплементация("ПоискСправочникаИнтерфейс");
Контрагент  = Декоратор2.НайтиКонтрагента(Данные);

Декоратор1 - в данном примере так же тип интерфейс, вот тут наглядно представлена польза абстракции.

 

Вот результат 

хотя как мы видим вызов метода происходит один раз.


В итоге у нас вышла такая реализация

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

Спасибо за внимание!

Вступайте в нашу телеграмм-группу Инфостарт

ООП pattern Decorator GoF в

См. также

Рефакторинг и качество кода Нейросети Программист 1С:Предприятие 8 Бесплатно (free)

Продолжение статьи «BSL Language Server внутри 1С:EDT: коннектор, которого не хватало». Там мы научили EDT видеть расширенную диагностику BSLLS, а здесь замкнем контур: научим ИИ-агентов автоматически исправлять эти ошибки строго по официальным стандартам разработки 1С.

02.09.2026    1314    malikov_pro    2    

6

Нейросети Рефакторинг и качество кода Программист 1С 8.3 Бесплатно (free)

В справочнике дополнительных обработок любой базы старше трёх лет лежит два-три десятка файлов. Часть писали вы, часть предыдущий разработчик, часть прислал подрядчик. Завтра одну из них надо править, и первый вопрос не "как править", а "что она вообще делает". Обычный ответ - открыть и читать: полторы тысячи строк это полдня. Показываю, как уложиться в пять минут: пять шагов, у каждого сказано, что он даёт. Внутри распределение 1 135 находок по ста чужим обработкам (четыре первых места из шести - одно и то же), что нашлось в наших собственных обработках, и честный список того, чего этот способ не даёт.

01.09.2026    1338    nedomolkov.ivan    6    

2

Инструментарий разработчика Нейросети Рефакторинг и качество кода Программист 1С 8.3 Абонемент ($m)

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

10 стартмани

01.09.2026    512    1    nedomolkov.ivan    5    

1

Рефакторинг и качество кода Нейросети Программист 1С:Предприятие 8 Бесплатно (free)

Рассказываю, как подключить к языковым моделям (в Cursor, VS Code, Claude Code) настоящий Синтакс-помощник 1С - со всеми типами, методами, параметрами, примерами кода, контекстами вызова и версиями платформы. Без ручного парсинга HTML: плагин для 1C:EDT в один клик выгружает официальную справку в Docker-контейнер с MCP-сервером и гибридным поиском (FTS5 + векторный индекс).

01.09.2026    1214    malikov_pro    5    

4

Рефакторинг и качество кода Программист 1С 8.3 Бесплатно (free)

Синтаксический контроль прошёл, валидатор формы прошёл, сборка прошла, автопрогон написал что ошибок нет. Через час четыре падения подряд, все на том, что мы сами не нажимали. Разбираю все четыре, включая самое коварное: загрузчик молча выбрасывает элемент формы из-за одной буквы в теге, и отладка уходит в модуль, где всё правильно.

01.09.2026    894    nedomolkov.ivan    0    

2

Рефакторинг и качество кода Программист 1С:Предприятие 8 Бесплатно (free)

Если вы разрабатываете в 1C:EDT, то наверняка знакомы со штатной системой статического анализа через плагин 1C:Code style V8. Но вы также могли заметить, что база встроенных правил давно не обновлялась: последний стабильный релиз плагина вышел ещё в декабре 2023 года. Чтобы вернуть в EDT свежие и актуальные проверки, я форкнул и доработал проект коннектора к BSL Language Server. В этой статье расскажу, как устроена интеграция, зачем она нужна в эпоху LLM и как подключить плагин за пять минут.

01.09.2026    941    malikov_pro    5    

4

Инструментарий разработчика Рефакторинг и качество кода Программист 1С 8.3 1С 8.5 Абонемент ($m)

Внешняя обработка для 1С, которая ищет в коде нарушения стандартов БСП и платформы (модальные вызовы, запросы в цикле, незакрытый привилегированный режим и др.) и часть из них чинит автоматически. Работает по фрагменту кода и по всей выгрузке конфигурации, с фоновым режимом через БСП и отчётом по найденному.

3 стартмани

27.08.2026    415    0    KonMa    0    

2
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. PerlAmutor 162 21.06.18 18:52 Сейчас в теме
Функция НайтиКонтрагента(Данные) Экспорт 
	Если ДанныеВерсии.Свойство("РежимПроверки") И ДанныеВерсии.РежимПроверки Тогда
		Возврат Неопределено;	
	КонецЕсли;


(0) Это можно немного улучшить, на мой взгляд, таким образом:

		Попытка
			 Выполнить(СтрШаблон("Объект.%1(, Истина)", Метод));
		Исключение
			 ОтсутствующиеМетоды.Добавить(Метод);
		КонецПопытки;
...
Функция НайтиКонтрагента(Данные = Неопределено, РежимПроверки = Ложь) Экспорт 
	Если РежимПроверки Тогда
		Возврат Неопределено;	
	КонецЕсли;
Показать
2. lazarenko 243 21.06.18 19:11 Сейчас в теме
(1) можно, только это ничего ж не меняет. Просто в моем варианте хорошо то, что параметр у метода один
3. PerlAmutor 162 21.06.18 19:22 Сейчас в теме
(2) Тоже верно. Тогда вопрос, тут ошибки нет случаем? А то параметр называется "Данные", а поиск свойства идет у "ДанныеВерсии":

Функция НайтиКонтрагента(Данные) Экспорт 
	Если ДанныеВерсии.Свойство("РежимПроверки") И ДанныеВерсии.РежимПроверки Тогда
		Возврат Неопределено;	
	КонецЕсли;
4. lazarenko 243 22.06.18 08:08 Сейчас в теме
(3) да это я ошибся когда в статью переносил, в приаттаченных обработках нор.
5. l1ike 16.07.18 07:52 Сейчас в теме
Ну раз уж интерфейсы в 1с появились, давайте уже и статические типы прикручивайте )))
Вы соответствие объекта интерфейсу когда проверять планируете? При старте программы или при создании объекта? Если при создании объекта, то выгода от интерфейсов, по моему, весьма сомнительна. А если при старте программы, тогда проще как в javascript транспиляторы писать.
6. s_vidyakin 68 11.01.19 18:08 Сейчас в теме
Данные = Новый Структура("ИНН, КПП", КакойтоИНН, КакойтоКПП); // Входящий параметр теперь один, структура.
Интерфейс = Обработки.ПоискСправочника.Создать().Имплементация("ПоискСправочникаИнтерфейс");
Декоратор1 = Обработки.Декоратор1.Создать().Наследовать(Интерфейс).Имплементация("ПоискСправочникаИнтерфейс");
Контрагент = Декоратор1.НайтиКонтрагента(Данные);

Не превращайте 1С в богомерзкую яву! ))
Для отправки сообщения требуется регистрация/авторизация