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

21.06.18

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

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

Скачать файл

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

Наименование По подписке [?] Купить один файл
Принципы ООП в 1С на примере реализации pattern Decorator:
.zip 12,71Kb
5
5 Скачать (1 SM) Купить за 1 850 руб.

 

Для начала ознакомимся с 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С v8.3 Бесплатно (free)

Расширяемый форматтер структуры модулей 1С. Умеет автоматически расставлять стандартные области и раскидывать по ним процедуры и функции модуля, оформлять стандартные комментарии к методам с помощью ИИ. Также умеет анализировать модуль - извлекать структуру вызовов, используемые поля и т.д. Реализован в виде расширения (.cfe). Можно использовать как платформу для обработки кода в своих задачах автоматизации разработки.

12.02.2025    3899    251    wonderboy    36    

105

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

В третьей статье по докладу Александра Кириллова, с которым он выступил на конференции INFOSTART TECH EVENT 2024, обсудим подходы к рефакторингу платформеннозависимого кода

11.02.2025    361    it-expertise    0    

2

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

Во второй статье по докладу Александра Кириллова, с которым он выступил на конференции INFOSTART TECH EVENT 2024, поговорим об особенностях анализа конфигурации 1С на наличие платформеннозависимого кода.

31.01.2025    1397    it-expertise    1    

7

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

В практике нашей специальной команды по проектам сложных обновлений 1С прошел один из самых объёмных проектов: необходимо было обновить «1С: Бухгалтерия предприятия КОРП 3.0 + БИТ.ФИНАНС». Конфигурация содержала доработки практически по всем типам объектов метаданных. Длительность проекта составила 1 год и 2 месяца и обеспечила полной загрузкой 4 разработчиков на 6 месяцев.

31.01.2025    880    1c-izh    2    

5

Рефакторинг и качество кода Программист Стажер Платформа 1С v8.3 1C:Бухгалтерия Бесплатно (free)

В последнее время термин «чистый код» стал очень популярным. Появились даже курсы по данной тематике. Так что же это такое?

16.09.2024    16810    markbraer    66    

43

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

В статье рассматривается отказ от использования процедур и унификация формата ответа функций. Способ описывается на примере развития абстрактной информационной системы, работающей с PDF файлами.

10.09.2024    1317    acces969    4    

6

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

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

28.08.2024    1807    Chernazem    3    

6

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

SOLID – принципы проектирования программных структур (модулей). Акроним S.O.L.I.D. образован из первой буквы пяти принципов. Эти принципы делают код более гибким, упрощают разработку. Принято считать, что принципы SOLID применимы только в объектно-ориентированном программировании. Но их можно успешно использовать и в 1С. Расскажем о том, как разобраться в принципах SOLID и начать применять их при работе в 1С.

22.08.2024    12140    alex_sayan    41    

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


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

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

Функция НайтиКонтрагента(Данные) Экспорт 
	Если ДанныеВерсии.Свойство("РежимПроверки") И ДанныеВерсии.РежимПроверки Тогда
		Возврат Неопределено;	
	КонецЕсли;
4. lazarenko 240 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С в богомерзкую яву! ))
Оставьте свое сообщение