ПРЕДУПРЕЖДЕНИЕ. Все ниженаписанное является плодом хронического недосыпания! Не пытайтесь повторить это в конфигураторе здорового человека. Работает только в 1С:EDT с плагином V8 Code Style, в идеале - с типизацией строгого режима @strict-types (но можно и без нее).
Приснилось мне как-то раз, что в 1С есть абстрактные интерфейсы.
Во сне мне для чего-то понадобилось хранить пары ключ-значение (кто сказал "Соответствие"? молодец, садись и слушай дальше).
А сколько есть в 1С способов реализации такого хранилища на сервере?
- Просто в оперативной памяти (объект Соответствие).
- Во временном хранилище (тот же объект Соответствие, помещенный во временное хранилище).
- В параметрах сеанса.
- В хранилище настроек пользователя.
- В регистре сведений.
- … (тут еще уйма вариантов)
И я подумал, что вдруг мне понадобятся разные варианты реализации. И надо бы подсунуть некоторой процедуре это хранилище таким способом, чтобы она ничего не знала о способе его реализации. Потому что, меньше знаешь - крепче спишь (девиз хорошей архитектуры, так-то).
А работал я в EDT. И решил я сделать обработку с именем ИХранилищеЗначений. А в модуле обработки описать программный интерфейс с пустыми методами. Вот такой:
// @strict-types
// @skip-check module-empty-method
#Если Сервер ИЛИ ВнешнееСоединение ИЛИ ТолстыйКлиентОбычноеПриложение Тогда
#Область ПрограммныйИнтерфейс
#Область ИХранилищеЗначений
// Прочитать значение по ключу.
//
// Параметры:
// Ключ - Произвольный
//
// Возвращаемое значение:
// Произвольный
//
Функция Прочитать(Знач Ключ) Экспорт
КонецФункции
// Записать значение по ключу.
//
// Параметры:
// Ключ - Произвольный
// Значение - Произвольный
//
Процедура Записать(Знач Ключ, Знач Значение) Экспорт
КонецПроцедуры
// Удалить значение по ключу.
//
// Параметры:
// Ключ - Произвольный
//
Процедура Удалить(Знач Ключ) Экспорт
КонецПроцедуры
#КонецОбласти
#КонецОбласти // ПрограммныйИнтерфейс
#Область Инициализация
ВызватьИсключение "Не надо создавать экземпляр абстрактного интерфейса, он вообще не для этого!";
#КонецОбласти
#КонецЕсли
Получилось у меня описание абстрактного интерфейса и новый тип ОбработкаОбъект.ИХранилищеЗначений.
Почему обработка, спросите вы? Ну, во-1х, это объект, порождающий новый тип (в отличие от общего модуля, например). Во-2х, это самый безобидный из объектов: он не создает никаких таблиц в информационной базе и имеет наименьшее количество собственных предопределенных методов и событий, которые нам в данном случае вообще не нужны, так что чем их меньше - тем лучше. У обработки их всего 5 (4 метода и 1 событие).
А потом я написал уж не помню какую процедуру вот таким образом:

Ну и здорово, подумал я: EDT выдает подсказку по всем методам интерфейса. Правда, в списке мельтешат предопределенные методы обработки, но с этим можно мириться. А если ошибиться с именем метода, то подчеркивает красненьким. При этом я еще даже не написал ни одного варианта реализации!
Дальше мне пришло в голову вот что. Полиморфизм в 1С — это хорошо, но иногда его бывает слишком много. Например, если процедура может получать объекты разных типов, то как понять, что за объект ей передали, и что с ним можно делать, а что нельзя? И при этом сохранять спокойный сон, по-прежнему ничего не зная о способе реализации объекта? Другими словами, нужно как-то узнавать, какой интерфейс реализует полученный объект. К слову, он ведь может реализовывать и больше одного интерфейса.
И тогда я измыслил абстрактнейший из абстрактных интерфейсов. Так и назвал его: ИАбстрактный. Тоже сделал в виде обработки, но на этот раз описал всё в модуле менеджера, для разнообразия. Он содержит всего один метод.
// @strict-types
// @skip-check module-empty-method
#Если Сервер ИЛИ ВнешнееСоединение ИЛИ ТолстыйКлиентОбычноеПриложение Тогда
#Область ПрограммныйИнтерфейс
#Область ИАбстрактный
// Проверяет, реализует ли объект указанный интерфейс.
//
// Параметры:
// ИмяИнтерфейса - Строка
//
// Возвращаемое значение:
// Булево
//
Функция РеализуетИнтерфейс(Знач ИмяИнтерфейса) Экспорт
КонецФункции
#КонецОбласти
#КонецОбласти // ПрограммныйИнтерфейс
#КонецЕсли
Теперь каждый приличный объект должен реализовать интерфейс ИАбстрактный, тогда можно будет, при помощи метода РеализуетИнтерфейс проверить, реализует ли он тот интерфейс, который от него ожидается.
// Еще какая-то процедура.
//
// Параметры:
// Объект - ОбработкаМенеджер.ИАбстрактный, ОбработкаОбъект.ИХранилищеЗначений -
//
Процедура ЕщеКакаяТоПроцедура(Знач Объект)
Если Объект.РеализуетИнтерфейс("ИХранилищеЗначений") Тогда
//...
КонецЕсли;
КонецПроцедуры
Ну а если вдруг объект не содержит метода РеализуетИнтерфейс, платформа выдаст исключение. Тоже своего рода ответ на вопрос.
А как же реализовать абстрактный интерфейс, спросите вы? А в виде любого серверного объекта, лишь бы он имел модуль, содержащий определения методов интерфейса. Это может быть модуль объекта, модуль набора записей, модуль менеджера, общий модуль, и даже модуль формы в серверном контексте.
Посмотрел я на все это и подумал, что это хорошо. И был вечер, и было утро, день шестой… так, стоп, это уже из другой сказки.
Слушайте, что дальше было. Приснилось мне, что в EDT появился объект Интерфейс, специально для описания абстрактных интерфейсов. И что теперь не нужно для этого плодить обработки, которые потом будут мертвым грузом висеть в конфигурации. И что поддерживается наследование одного интерфейса от другого, и плагин V8 Code Style контролирует, что реализация интерфейса в модуле совпадает с его описанием… А потом я проснулся.
КонецСказочки;
Вступайте в нашу телеграмм-группу Инфостарт