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

Исследуем примен автоматизацией ение ООП-подхода на примере сортировки коллекций. Вариантов для эмуляции объектов (экземпляров класса) средствами 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.

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

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

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

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

 

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

 

Файлы

Наименование Файл Версия Размер Кол. Скачив.
Примеры ООП
.dt 45,04Kb
1
.dt 45,04Kb 1 Скачать

Полная версия

© ООО "Инфостарт", 2006-2023 www.infostart.ru