Если хочется ООП с наследованием и полиморфизмом

21.07.22

Разработка - Математика и алгоритмы

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

Скачать файл

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

Наименование По подписке [?] Купить один файл
Примеры ООП
.dt 45,04Kb
1
1 Скачать (1 SM) Купить за 1 850 руб.

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

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

Создадим для примера класс (общий модуль) КлассБазовый, и определим в нем конструктор.

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

	Результат.Вставить("ТипОбъекта",Результат.Класс);

	Возврат Результат;
КонецФункции 
 

Функция ТипОбъекта(Объект) Экспорт
	Возврат Объект.Класс;
КонецФункции 

Таким образом, объект будет иметь одно поле Класс и метод получения значения этого поля - геттер ТипОбъекта(). Структура же, эмулирующая объект, кроме элемента Класс содержит еще и элемент с ключом ТипОбъекта и значением, равным ссылке на сам этот класс (общий модуль). Для чего это нужно? Предположим, что мы решили создать новый класс КлассНовый, наследник от КлассБазовый:

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

В конструкторе мы переопределим поле Класс, но метод ТипОбъекта() нас вполне устраивает, нам переопределять его не надо. При создании экземпляра класса КлассНовый значение элемента структуры ТипОбъекта будет унаследовано от класса КлассБазовый и не будет переопределено в конструкторе. Это означает, что мы, глядя на объект класса КлассНовый, увидим, что метод ТипОбъекта() определен в классе (общем модуле) КлассБазовый:

НовыйОбъект = КлассНовый.СоздатьОбъект();
Модуль = НовыйОбъект.ТипОбъекта;
Сообщить(Модуль.ТипОбъекта(НовыйОбъект)); 

или, покороче:

НовыйОбъект = КлассНовый.СоздатьОбъект();
Сообщить(НовыйОбъект.ТипОбъекта.ТипОбъекта(НовыйОбъект)); 

Конструкция "НовыйОбъект.ТипОбъекта.ТипОбъекта(НовыйОбъект)" выглядит... м-м-м странно и наверняка вызовет язвительную усмешку у тру-ООП-программистов, но мы же проводим исследование, верно? Зато такой подход позволяет эмулировать позднее связывание, т.е. когда только в момент вызова определяется какой из методов вызывать, а также дает возможность эмулировать таблицу виртуальных методов - место хранения ссылок на методы классов. Таблица здесь не является таблицей в прямом смысле этого слова, она "размазана" по элементам структур разных классов. 

Более подробный пример для класса КлассУпорядоченнаяКоллекция:

Функция СоздатьОбъект()Экспорт
	// наследуем поля и методы класса-родителя
	Результат = КлассБазовый.СоздатьОбъект();
	
	// Поля
	Результат.Вставить("Класс",КлассУпорядоченнаяКоллекция);
	Результат.Вставить("Предмет");
	
	// Абстрактные методы, которые не определены в этом классе
	Результат.Вставить("ВывестиЭлемент");
	
	// Новые методы
	Результат.Вставить("Количество", Результат.Класс);
	Результат.Вставить("Получить", Результат.Класс);
	Результат.Вставить("Вывести", Результат.Класс);
	
	Возврат Результат;
КонецФункции 


Функция Количество(Объект)Экспорт
	Возврат Объект.Предмет.Количество();
КонецФункции 

Функция Получить(Объект, Индекс)Экспорт
	Возврат Объект.Предмет.Получить(Индекс);
КонецФункции 

Процедура Вывести(Объект)Экспорт
	ВГраница = Объект.Количество.Количество(Объект) - 1;
	Для Индекс = 0 По ВГраница Цикл  
		Элемент = Объект.Получить.Получить(Объект, Индекс);
		Объект.ВывестиЭлемент.ВывестиЭлемент(Объект, Элемент);
	КонецЦикла; 	
КонецПроцедуры

Предмет здесь - некая коллекция (Массив, СписокЗначений, ТаблицаЗначений), для которой определено отношение порядка, т.е. каждый элемент имеет свой порядковый номер - индекс.

Для этого класса определены очевидные методы Количество() и Получить(), а вот с методом Вывести() ситуация интереснее. Алгоритм вывода коллекции простой - в цикле от 0 до верхней границы получаем очередной элемент и выводим его. Вполне возможна ситуация, когда у какого-либо потомка появится свой, переопределенный метод Количество() или метод Получить(). Поэтому вызов этих методов происходит посредством обращения к элементам структуры-объекта, содержащим ссылки на общие модули. Методы, которые можно переопределить в классах-потомках называются виртуальными методами. Метод же ВывестиЭлемент() вообще не определен для этого класса (в этом общем модуле). Предполагается, что этот метод должен быть определен в классе-потомке (необязательно потомке первого уровня!). Такие методы, как ВывестиЭлемент(), называются абстрактными методами, а классы с такими методами - абстрактные классы.

Вернемся однако к нашей основной задаче - сортировке. Я не буду останавливаться на процессе проектирования, а сразу покажу результат:

Иерархия классов:

Наследование методов для КлассМассивЧисловой и КлассМассивСтруктур:

Здесь жирным шрифтом помечены методы, определенные или переопределенные в классе, серым цветом - унаследованные, курсивом - абстрактные методы.

Похожим образом определен и класс КлассСписокЗначений.

Процедура сортировки описана в абстрактном классе КлассУпорядоченнаяКоллекция, она использует приватный (не экспортный) метод СравнитьИПоменять()

Процедура Сортировать(Объект)Экспорт
	ВГраница = Объект.Количество.Количество(Объект) - 1;
	Для Индекс = 1 По ВГраница Цикл  		
		Индекс2 = Индекс;
		Пока Индекс2 > 0 Цикл
			Если Не СравнитьИПоменять(Объект, Индекс2 - 1, Индекс2) Тогда
				прервать;
			КонецЕсли; 
			Индекс2 = Индекс2 - 1;
		КонецЦикла; 		
	КонецЦикла; 	
КонецПроцедуры

Функция СравнитьИПоменять(Объект, Знач Индекс1, Знач Индекс2)
	Результат = Ложь;	
	Элемент1 = Объект.Получить.Получить(Объект, Индекс1);
	Элемент2 = Объект.Получить.Получить(Объект, Индекс2);
	Если Объект.СравнитьЭлементы.СравнитьЭлементы(Объект, Элемент1, Элемент2) Тогда
		Объект.Установить.Установить(Объект, Индекс1, Элемент2);
		Объект.Установить.Установить(Объект, Индекс2, Элемент1);
		Результат = Истина;
	КонецЕсли; 
	Возврат Результат;
КонецФункции 

Методы СравнитьЭлементы() определены в классах-потомках последнего уровня, но это не мешает их использовать в процедуре Сортировать() у предка. 

Метод СравнитьЭлементы() класса КлассМассивЧисловой:

Функция СравнитьЭлементы(Объект, Элемент1, Элемент2)Экспорт
	Возврат Элемент1 > Элемент2;
КонецФункции 

Что же у нас получилось в итоге такого моделирования ООП?

  • Инкапсуляция - ну, что-то подобное есть: поля и методы сгруппированы и "принадлежат" отдельным сущностям. Однако никакой защиты, изоляции и сокрытия этих данных нет. К полям есть доступ отовсюду, можно даже удалить любое поле объекта. "Таблица виртуальных методов" не защищена от порчи.
  • Наследование - определенно, есть. Поля наследуются, публичные методы - виртуальные, приватные методы не наследуются. Несложно реализовать множественное наследование - наследование от нескольких родителей.
  • Полиморфизм - есть и даже, наверное, избыточен и бесконтролен. Благодаря отсутствию контроля типов поле может принимать значения разных типов в объектах-наследниках. Методы могут переопределяться без ограничений. В методах классов-наследников могут быть добавлены новые (необязательные) параметры.
  • Абстракция - есть, и это, возможно, самое главное. В рассмотренном примере реализован алгоритм сортировки абстрактной коллекции, который не зависит от конкретной реализации вспомогательных методов получения, установки и сравнения отдельных элементов коллекции. 

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

А теперь о картинке в заголовке статьи. 

Мне кажется, она великолепно описывает попытки внедрения в 1С механизмов, для которых 1С не предназначена. Раскрашенные пальмы и бамбук могут заменить березовую рощу только в очень редких случаях (например когда заказчик рассматривает заросли с расстояния нескольких сотен метров). При этом надо учитывать дополнительные затраты на краску, кисти и работу. Поддержка тоже усложняется - необходимо все это регулярно подкрашивать. Так что же, получается, что всем этим вообще не стоит заниматься? Вовсе нет, напротив! Приобретается дополнительный опыт по работе с лакокрасочными материалами, работник получает некое морально-эстетическое удовлетворение, да и вообще, боец должен быть всегда занят. На мой взгляд, самый правильный подход - отличать деятельность, направленную на совершенствование навыков и получение положительных эмоций, от деятельности по созданию продуктов. В последнем случае главным аргументом должно являться соотношение результата, для получения которого нужен продукт, и затрат (денежных, временных, нематериальных). И тогда использование простых и надежных инструментов обычно становится предпочтительным.

Необходимо ли полноценное ООП в 1С? На мой взгляд, при разработке в мире 1С существует не так много задач, решение которых с использованием ООП давало бы существенный выигрыш по сравнению с обычным процедурным подходом. Из своего опыта, единственное, что могу припомнить - неплохо было бы иметь наследование форм или их частей с наследованием реквизитов, элементов и обработчиков. Но как совместить такое наследование с возможностью редактировать формы в конфигураторе и обеспечить надежность и удобство всего этого процесса, я не представляю - те зачатки наследования, которые уже есть, далеко не образец дружелюбного механизма. Хотелось бы, чтобы усилия разработчиков платформы были направлены прежде всего на совершенствование текущей предметно-процедурной методологии разработки, устранение методических ошибок, доработку недоделанных механизмов и исправление ошибок.

К статье приложена конфигурация с примерами сортировок числового массива, массива структур "Фамилия,Имя,Отчество" и списка значений (дата - представление даты). Работа проверялась на платформе 8.3.18.1363.

 
 По настоятельной просьбе модератора выкладываю скриншот конфигурации

На этом всё. Как всегда, приветствуются замечания / дополнения / комментарии.

Предыдущая статья:

Следующая статья:

 

 
 Некоторые из прочих моих публикаций

 

ООП парадигма объектно-ориентированное программирование наследование полиморфизм абстракция классы виртуальные методы

См. также

Языки и среды Программист Платформа 1С v8.3 Бесплатно (free)

Будем писать свои скрипты на питоне и запускать их на 1С.

15.04.2024    4198    YA_418728146    13    

62

Мобильная разработка Языки и среды 1С:Элемент Программист Бесплатно (free)

Flutter может быть использован с 1С:Предприятием для разработки кроссплатформенных мобильных приложений, обеспечивая единый интерфейс и функциональность на устройствах под управлением iOS и Android. Это позволяет создавать приложения с высокой производительностью благодаря использованию собственного движка рендеринга Flutter. Интеграция Flutter с 1С:Предприятием позволяет создавать мобильные приложения любого уровня сложности, интегрировать их в корпоративные информационные системы, а также реализовывать бизнес-логику

19.03.2024    18823    ROk_dev    74    

43

Математика и алгоритмы Программист Платформа 1C v8.2 Конфигурации 1cv8 Россия Абонемент ($m)

На написание данной работы меня вдохновила работа @glassman «Переход на ClickHouse для анализа метрик». Автор анализирует большой объем данных, много миллионов строк, и убедительно доказывает, что ClickHouse справляется лучше PostgreSQL. Я же покажу как можно сократить объем данных в 49.9 раз при этом: 1. Сохранить значения локальных экстремумов 2. Отклонения от реальных значений имеют наперед заданную допустимую погрешность.

1 стартмани

30.01.2024    3458    stopa85    12    

38

Языки и среды Программист Стажер Платформа 1С v8.3 Бесплатно (free)

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

16.01.2024    7512    SeiOkami    25    

62

Математика и алгоритмы Бесплатно (free)

Разработка алгоритма, построенного на модели симплекс-метода, для нахождения оптимального раскроя.

19.10.2023    7951    user1959478    52    

36

Математика и алгоритмы Разное Платформа 1С v8.3 Конфигурации 1cv8 Россия Абонемент ($m)

Расширение (+ обработка) представляют собою математический тренажер. Ваш ребенок сможет проверить свои знание на математические вычисление до 100.

2 стартмани

29.09.2023    3396    maksa2005    8    

26

Математика и алгоритмы Инструментарий разработчика Программист Платформа 1С v8.3 Мобильная платформа Россия Абонемент ($m)

Что ж... лучше поздно, чем никогда. Подсистема 1С для работы с регулярными выражениями: разбор выражения, проверка на соответствие шаблону, поиск вхождений в тексте.

1 стартмани

09.06.2023    11150    8    SpaceOfMyHead    19    

61

Языки и среды Инструментарий разработчика Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Вставки кода на C# внутри кода на 1С.

7 стартмани

07.04.2023    10620    4    SerVer1C    58    

45
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. a_a_burlakov 288 21.07.22 14:01 Сейчас в теме
Если хочется ООП с наследованием и полиморфизмом...
Если хочется функционального программирования с функциями высшего порядка и map, filter, reduce...
Если хочется низко-низкоуровневого программирования с битами и байтами...

Ответ, по-моему, один: переходите на другие языки. Наша 1С - она особа весьма специфичная и неприхотливая. Это как девушка, которая выросла и работает в деревне. Её не нужны цветы, конфеты и прочий синтаксический сахар, у неё любимый шрифт - это древний и уродливый Courier New. Но вот крепким хозяйственникам она очень нравится: она многого не требует, кучу денег не забирает, косметикой не балуется, но и трактор заведёт, и поле вспашет, и скотину не потеряет. Правда, и в своё хозяйство не пускает кого попало. Словом, молодец девка, но на любителя. А тем, кто любит вот эти все шуры-муры, красоту и цветочки - нужно к столичным барышням обращаться.

А на 1С натягивать ООП, низкоуровневое и функциональное программирование - это всё равно что сельской девушке дать Mercedes Benz или Lamborghini. Ради шутки можно, но ей это в хозяйстве не нужно. Даже если её посадить за Lamborgini, она будет на свой трактор оглядываться - так воспитана...
reckir; cheshirshik; abeliavtsev; mysm; Sejix; PLAstic; Alxby; Jeka44; PowerBoy; +9 Ответить
2. Alxby 1116 21.07.22 14:12 Сейчас в теме
3. Alxby 1116 21.07.22 14:19 Сейчас в теме
(2)Я ведь не зря вставил такую картинку в статью - у кого-то ностальгия, вызванная импринтингом, кто-то прочитал "Java за две недели", а кто-то хочет чистый код по Мартину. В этом нет ничего плохого - поиграться и вернуться к крепкому хозяйству.
a_a_burlakov; +1 Ответить
4. a_a_burlakov 288 21.07.22 14:22 Сейчас в теме
(3) Да, я согласен, и свой пост не в упрёк написал, и с выводами в самой статье согласен. )
5. TimurD 6 21.07.22 14:55 Сейчас в теме
Согласен, что полноценного ООП сейчас внедрять не нужно в 1С (возможно в отдаленном будущем). Но наследование и полиморфизм кто бы что не говорил - очень крутая штука (в тему про абстрактные объекты, формы и пр.). Самого посещают мысли сделать (пусть и ограниченно) наследование и полиморфизм, скажем, в виде плагина на ЕДТ. Но пока интересной мысли не пришло в голову как это в текущей парадигме 1С реализовать.
6. Alxby 1116 21.07.22 15:10 Сейчас в теме
(5)Наследование и полиморфизм в первую очередь требуется для сокращения объема кода при описании схожего функционала для разных сущностей. Для решения большинства задач 1С (не для всех) можно выделить общий код в отдельный метод и оставаться в рамках процедурного подхода. С формами, не с кодом, - да, не помешало бы.
7. PLAstic 296 22.07.22 10:09 Сейчас в теме
Не понимаю, зачем...

У меня 20+ лет в 1С из них примерно 10 во франче и я не могу привести практических примеров, когда бы мы такие сели и задумались "даа... а вот был бы у нас полиморфизм..."
Я пришёл после Borland C++ Builder, где ООП вполне было и оно там было востребовано. Здесь же это в принципе не надо, здесь Предметно-Ориентированное Программирование.
8. Alxby 1116 22.07.22 10:19 Сейчас в теме
(7)Я с Вами согласен, но найдется и много несогласных: "Нуралиев! Дай нам ООП!. Почему 1С не развивается? Там даже ООП нету! ". А объяснить, зачем оно нужно, обычно не могут.
9. cheshirshik 70 05.03.23 16:04 Сейчас в теме
Тем не менее сама 1с иногда использует подходы ООП в своих типовых конфигурациях. Например я нечто похожее видел в ЗУП. Не типовое использование обработки, когда по сути обработка представляет в себе некий объект принимающий в эскпортные переменные (как в свойства) какие-то данные и выдающая на выходе в такую же экспортную перменную некий результат, а расчет происходит внутри обработки в закрытых процедурах и функциях.
10. Alxby 1116 05.03.23 16:46 Сейчас в теме
(9)Вполне может быть. Идея с обработкой в общем-то лежит на поверхности. Здесь на сайте есть не одна статья о таком подходе.
cheshirshik; +1 Ответить
11. cheshirshik 70 05.03.23 20:52 Сейчас в теме
(10)
Речь не о идеи, а о практическом примирением. 😉 Причём самим вендером. 😀
Оставьте свое сообщение