Описание класса в конфигурации
Для описания класса в конфигурации создаем обработку. Далее эту обработку будем называть «описание класса» или «класс». Имя описания класса должно начинаться с буквы «к» (русская буква). Например, имя класса: «кПростоеСообщение». В реквизитах обработки (описание класса) должны быть созданы в обязательном порядке реквизиты (свойства): «Родитель». «Объект». Тип у данных реквизитов – «Произвольный». Реквизит «Родитель», после создания объекта, будет содержать объект родитель. А реквизит «Объект», после создания объекта, всегда содержит сам созданный объект. Причем, данное значение будет установлено у свойств «Объект» всех родительских объектов в том числе. Т.е., обращаясь к реквизиту «Объект» внутри любого родительского объекта (обработки), мы получим ссылку на объект, в рамках которого создан текущий родительский объект (обработка).
Рис.1
В модуле объекта обработки можно написать конструктор и/или деструктор объекта. Процедура конструктора объекта может содержать до 16 формальных параметров, которые могут быть заданы в последующем при создании объекта. Процедура деструктора параметров не имеет. Процедуры конструктора и деструктора должны быть экспортными. Данные процедуры будут вызваны автоматически при создании и уничтожении объекта соответственно. Еще раз акцентирую внимание, что процедуры конструктора и деструктора могут отсутствовать.
Рис.2
Далее, в обработке (описание класса) создаются требуемые реквизиты, которые будут играть роль свойств объекта. Далее – «свойства», «свойства объекта». Таким образом, все свойства объекта являются публичными.
Рис.3
Далее, в модуле обработки (описание класса) создаются процедуры и функции, требуемые для реализации логики работы объекта. Все процедуры и функции, которые будут являться методами объекта, должны быть объявлены экспортными. В данном примере, методы реализованы максимально просто для простоты понимания. Забегая вперед скажу, то такой способ вызова методов «ПолучитьПрефикс», «ПолучитьПостфикс» из метода «ВывестиСообщение» не позволит нам переопределить их в потомке. Далее, мы будем усложнять вызовы для реализации переопределения методов в потомках.
Рис.4
Описание класса довольно простого объекта мы сделали. Далее, будем использовать описание данного класса для создания объектов.
Создание объекта на основании описанного класса
Объект может быть создан на основании описания класса четырьмя способами: на основании имени класса, на основании структуры с именем класса, на основании уже созданного объекта прототипа заданного класса, на основании метаданных обработки конфигурации. Для всех указанных способов создания объекта используется функция глобального модуля «оСоздатьОбъект». Отличие заключается в том, как задается имя класса создаваемого объекта.
Создание объекта на основании имени класса. Самый простой способ создания объекта.
Рис.5
Создание объекта на основании структуры с именем класса.
Рис.6
Создание объекта на основании уже созданного объекта прототипа заданного класса. При таком способе создания, копирование свойств объекта прототипа в создаваемый объект не происходит. Объект основание (прототип) используется только как источник имени класса.
Рис.7
Создание объекта на основании метаданных обработки конфигурации.
Ри.8
Наследование свойств и методов
Одним из ключевых особенностей Объектно-Ориентированного Программирования (ООП) является понятие: «наследование». Под данным определением понимается доступность всех опубликованных свойств и методов родителя в объекте потомке. Наследование реализуется путем создания объекта родителя в конструкторе создаваемого объекта. Проиллюстрируем на примере. Создадим класс потомок «кФорматСообщение» на основании родительского класса «кПростоеСообщение». Для этого создаем новое описание класса (обработку) с именем «кФорматСообщение», и в модуле объекта создаем процедуру конструктор. При создании нового класса (обработки) не забываем про обязательные реквизиты «Родитель» и «Объект». В процедуре конструктора объекта создаем объект родитель (см. Рис. ниже).
Рис.9
Т.е., жесткого наследования как такового нет. Наследование определяется алгоритмом в конструкторе объекта и можно создавать в конструкторе разных родителей в зависимости от ситуации. После создания объекта переопределять свойство «Родитель» нельзя, т.к. в свойство «Объект» всех родительских объектов записывается созданный объект потомок. Ну если «хочется», то можно, но нужно понимать последствия.
Если вы не задаете родителя в конструкторе, то родителем создаваемого объекта всегда будет объект, созданный на основании класса «кКласс». Создание данного родителя производится уже после выполнения конструктора объекта в случае если свойство «Родитель» не является объектом (обработкой).
Для чтения, установки свойств объекта вне зависимости от его нахождения в иерархии объектов нужно использовать функцию глобального модуля «оСвойство».
Рис.10
Рис.11
Для вызова методов объекта вне зависимости от его нахождения в иерархии объектов нужно использовать процедуру глобального модуля «оПроцедура» и функцию глобального модуля «оФункция». При использовании данной процедуры и функции можно задать до 16 параметров, которые будут переданы в соответствующий вызываемый метод (процедуру или функцию) объекта.
Рис.12
Полиморфизм свойств и методов
Еще одним из ключевых особенностей Объектно-Ориентированного Программирования (ООП) является понятие: «полиморфизм». Под полиморфизмом понимается изменение свойств и методов в объекте потомке по сравнению с объектом родителем.
Поясним на примере. Допустим, что в определении класса «кПростоеСообщение» мы задали длину свойства «ТекстПрефикса» равную 10 символам. Переопределим это свойство в классе потомке «кФорматСообщение».
Рис.13
Рис.14
Для того, чтобы переопределяемое свойство было задействовано взамен «старого» при работе алгоритмов, в том числе и в алгоритмах методов объекта, необходимо обращаться к свойству, используя функцию глобального модуля «оСвойство». Изменим в соответствии с этим алгоритмы методов родительского объекта «кПростоеСообщение».
Рис.15
Теперь при работе методов «ПолучитьПрефикс», «ПолучитьПостфикс», «ВывестиСообщение» будут использованы свойства «ТекстПрефикса», «ТекстПостфикса», «ТекстСообщения», которые могут быть переопределенны в объектах потомках. В нашем случае, мы в объекте потомке переопределили свойство «ТекстПрефикса».
Важное замечание: в конструкторе объекта использовать обращение к свойствам, используя функцию «оСвойство», можно только для родительских объектов. Это связано с тем, что инициализация свойств «Родитель» и «Объект» еще не завершена в полной мере.
Рис.16
По этой причине, в нашем примере, необходимо переопределяемому свойству «ТекстПрефикса» присвоить значение в конструкторе объекта потомка.
Рис.17
Или вот так
Рис.18
Выводы: При разработке алгоритмов методов объектов нужно придерживаться определенных правил. Если предполагается, что свойство объекта может быть переопределено и мы в своем алгоритме должны использовать именно переопределенное в потомке свойство, то соответственно для работы со свойством нужно использовать функцию глобального модуля «оСвойство». А для получения объекта, в рамках которого был создан текущий объект, необходимо использовать свойство «Объект». Свойство «Объект» должно быть у всех объектов по определению (см. «Описание класса в конфигурации»).
Свойство «Объект», после создания объекта, всегда содержит сам созданный объект. Причем, данное значение будет установлено у свойств «Объект» всех родительских объектов в том числе. Т.е. обращаясь к реквизиту «Объект» внутри любого родительского объекта, мы получим ссылку на объект, в рамках которого создан сам родительский объект («масло масленое» - но другого описания не придумал).
Как было указано ранее, для вызова методов объекта, вне зависимости от его нахождения в иерархии объектов, нужно использовать процедуру глобального модуля «оПроцедура» и функцию глобального модуля «оФункция». Рассмотрим переопределение методов объекта.
Для начала рассмотрим случай, когда метод вызывается вне алгоритмов самого объекта. В этом случае, в классе потомке просто добавляется процедура или функция с названием аналогичным методу в классе родителе или прародителе. Причем, может быть переопределено количество параметров, логика работы, или даже произведена смена процедуры на функцию или наоборот. В новом (переопределенном) методе обращение к методу родителя возможно через свойство «Родитель».
Переопределим, в нашем примере, в объекте потомке «кФорматСообщение» метод «ВывестиСообщение». Переопределим количество параметров и заменим полностью логику работы метода.
Рис.19
Или мы можем сделать вот так – используем, в том числе, в переопределяемом методе вызов метода родителя.
Рис.20
Соответственно теперь мы можем вызвать метод «ВывестиСообщение» следующим образом:
Рис.21
Теперь рассмотрим случай, когда метод вызывается в алгоритмах самого объекта. Также, как и при работе со свойствами объекта, если предполагается, что метод объекта может быть переопределен, и мы в своем алгоритме должны использовать именно переопределенный в потомке метод, то соответственно для вызова метода нужно использовать процедуру глобального модуля «оПроцедура» и функцию глобального модуля «оФункция». А для получения объекта, в рамках которого был создан текущий объект, необходимо использовать свойство «Объект». Свойство «Объект» должно быть у всех объектов по определению (см. «Описание класса в конфигурации»).
В нашем примере исходный класс «кПростоеСообщение» имеет метод «Вывести сообщение», который вызывает методы «ПолучитьПрефикс» и «ПолучитьПостфикс» для получения строк префикса и постфикса соответственно.
Рис.22
Переопределим в классе «кФорматСообщение» потомке методы «ПолучитьПрефикс» и «ПолучитьПостфикс». Данные переопределенные методы будут вызываться из метода «Вывести сообщение», который расположен в родителе.
Рис.23
Здесь еще раз стоит обратить внимание на вызов методов в классе родителя. А именно, на способе получения объекта, в рамках которого был создан текущий объект родитель.
Рис.24
Уничтожение объекта
Объект может быть уничтожен. Для этого необходимо использовать процедуру глобального модуля «оУничтожитьОбъект». В качестве единственного параметра процедура принимает уничтожаемый объект. Основным назначением данной процедуры является вызов метода деструктора объекта.
Рис.25
При этом будет вызван деструктор родительского объекта в том числе.
Рис.26
Использование внешних обработок для описания класса
Для описания класса можно использовать внешние обработки. Далее - «Внешний класс», «Внешнее описание класса». Все написанное выше, справедливо и в этом случае. Отличие заключается только в том, что предварительно внешний класс нужно подключить.
Создадим внешнее описание класса.
Рис.27
В модуле объекта обработки определим методы внешнего класса.
Рис.28
Для использования внешнего описания класса нужно его подключить. Это можно сделать следующими способами:
Рис.29
Или вот так
Рис.30
Более подробно описание параметров функций подключения внешнего описания классов можно посмотреть в общем глобальном модуле «ООП».
Подключенные внешние классы после подключения ничем не отличаются от встроенных. Поэтому классы можно использовать совместно. Например, сделать встроенный класс, который будет являться потомком внешнего класса и т.п.
Подключение внешних описаний классов через функционал внешних алгоритмов
Раздел удален, т.к. не актуален для типовых конфигураций.
Полный перечень функций глобального модуля для работы с ООП
Все указанные ниже процедуры и функции находятся в общем глобальном модуле «ООП». Указанные процедуры и функции доступны только на стороне сервера.
№ |
Имя процедуры или функции |
Краткое описание |
1 |
оПодключитьКлассы |
Функция производит подключение для дальнейшего использования указанных в параметре классов. |
2 |
оЗагрузитьКлассы |
Функция производит загрузку указанных в параметре классов (обработок) и возвращает информацию необходимую для последующего подключения классов с помощью функции "оПодключитьКлассы". |
3 |
оИспользоватьКлассы |
Функция производит загрузку указанных в параметре классов (обработок) и их подключение для дальнейшего использования |
4 |
оЭтоВстроенныйКласс |
Функция по имени класса определяет является ли указанный класс встроенным в конфигурацию. |
5 |
оСоздатьОбъект |
Функция производит создание объекта (обработки) с вызовом процедуры конструктора объекта. |
6 |
оУничтожитьОбъект |
Процедура для уничтожения объекта. Основная ее задача вызвать процедуру деструктора объекта. |
7 |
оЭтоОбъект |
Функция проверяет является ли проверяемое значение объектом (обработкой). |
8 |
оПолучитьИмяКласса |
Функция возвращает имя класса объекта. |
9 |
оЕстьСвойство |
Функция проверяет наличие указанного свойства у объекта. Просмотр по иерархии объектов не производится. |
10 |
оВыразитьКак |
Функция возвращает объект заданного класса в иерархии объектов из которых состоит текущий объект. |
11 |
оМожноВыразитьКак |
Почти тоже самое что и «оВыразитьКак» только без конкретики. |
12 |
оПолучитьРодителя |
Функция возвращает непосредственного родителя указанного объекта. |
13 |
оПолучитьПрародителя |
Функция возвращает прародителя указанного объекта. |
14 |
оСвойство |
Функция производит чтение или установку значения указанному свойству объекта. |
15 |
оФункция |
Функция выполняет указанный метод (функцию) объекта и возвращает значение возвращаемое выполненной функцией. |
16 |
оПроцедура |
Процедура выполняет указанный метод (процедуру) объекта. |
Интерфейс класса, работа с интерфейсом класса
«Интерфейс» – это специальный объект для работы на стороне клиента управляемого приложения. Технически – это управляемая форма обработки, далее по тексту «Интерфейс». Интерфейс - это «родственник» объекта по классу. Интерфейс вне класса не существует. У класса может быть много интерфейсов. Интерфейс - это объект который можно создать только на клиенте. Этот объект предоставляет набор свойств и методов для их вызова на клиенте. Объект «Интерфейс» наследование не поддерживает.
Создадим интерфейс у нашего класса «кФорматСообщение».
Рис.36
В модуле интерфейса (управляемой формы) можно написать конструктор и/или деструктор объекта. Процедура конструктора может содержать до 16 формальных параметров, которые могут быть заданы в последующем при создании интерфейса. Процедура деструктора параметров не имеет. Процедуры конструктора и деструктора должны быть экспортными, объявленными на клиенте. Данные процедуры будут вызваны автоматически при создании и уничтожении интерфейса соответственно. Еще раз акцентирую внимание, что процедуры конструктора и деструктора могут отсутствовать. И еще раз акцентирую внимание, что процедуры конструктора и деструктора, в случае их присутствия, должны быть объявлены как клиентские.
Рис.37
Далее, в управляемой форме создаются требуемые реквизиты, которые будут играть роль свойств интерфейса. Далее – «свойства интерфейса». Таким образом, все свойства интерфейса являются публичными.
Рис.38
Далее, в модуле управляемой формы создаются процедуры и функции требуемые для реализации логики работы интерфейса. Все процедуры и функции, которые будут являться методами интерфейса, должны быть объявлены экспортными.
Рис.39
Простой интерфейс класса определили.
Теперь приведем пример использования интерфейса.
Рис.40
Посмотрим еще раз на метод «ВывестиПредупреждающееСообщение» интерфейса. Этот клиентский метод вызывает серверную процедуру «ВывестиПредупреждающееСообщениеСервер», в которой производится создание объекта класса «кФорматСообщение». Причем, создание объекта производится на основании интерфейса (управляемой формы обработки).
Рис.41
Выводы: интерфейс предназначен для возможности инициировать какие-либо действия на клиенте, связанные с определенным нами классом. Для внешних классов все выше описанное также справедливо после подключения соответствующего класса.
Полный перечень функций глобального модуля для работы с ИНТЕРФЕЙСОМ
Все указанные ниже процедуры и функции находятся в общем глобальном модуле «ООПИнтерфейс». Функции создания и уничтожения интерфейса доступны только на клиенте, остальные функции доступны и на клиенте, и на сервере.
№ |
Имя процедуры или функции |
Область видимости |
Краткое описание |
1 |
оСоздатьИнтерфейс |
Клиент |
Функция производит создание нового интерфейса (управляемой формы обработки) указанного класса с вызовом процедуры конструктора. |
2 |
оУничтожитьИнтерфейс |
Клиент |
Процедура для уничтожения интерфейса. Основная ее задача вызвать процедуру деструктора интерфейса. |
3 |
оЭтоИнтерфейс |
Клиент, Сервер |
Функция проверяет является ли заданное значение интерфейсом (управляемой формой обработки). |
4 |
оПолучитьИмяКлассаИзИнтерфейса |
Клиент, Сервер |
Функция возвращает имя класса из интерфейса. |
5 |
оПолучитьИмяИнтерфейса |
Клиент, Сервер |
Функция возвращает имя интерфейса. |
Установка механизма ООП
Работа механизма ООП проверена на версиях платформы: 8.2.19.83, 8.3.15.1700.
Для установки механизма нужно в целевую конфигурацию из прилагаемой конфигурации добавить следующие объекты метаданных:
Рис.42
Важное замечание: для правильной работы механизма в свойстве конфигурации «Вариант встроенного языка» должно быть выставлено значение «Русский».
Рис.43
Создание классов потомков на основании базовых классов 1С
На основании данного механизма также можно определять новые классы, которые будут иметь в качестве родителя базовые классы 1С.
Для примера, сделаем новый класс «ТаблицаЗначенийРасширенная», который будет являться потомком базового класса «ТаблицаЗначений». Определим конструктор и деструктор объекта. В конструкторе объекта, в качестве родителя, как раз и будет создаваться базовый класс 1С «ТаблицаЗначений».
Рис.44
Можно усложнить конструктор, чтобы иметь возможность создавать объект на основании уже имеющейся таблицы значений.
Рис.45
Для правильной работы механизма ООП, необходимо внести небольшое изменение в общий модуль «ООП», в функцию «оЭтоОбъект». Нужно определить, что базовый класс 1С «ТаблицаЗначений» является родным для механизма ООП.
Рис.45
Определим в нашем новом классе метод-функцию, которая будет нам возвращать массив структур, созданный из данных таблицы значений.
Рис.46
Теперь можно использовать наш новый класс.
Рис.47
Приложение
Файл конфигурации с механизмом ООП: «1Cv8_2_ООП_Чистая_20200409_1849.cf».