К великому нашему прискорбию в 1С 8.0 не включено объектно-ориентированное программирование. Не будем обсуждать в данной статье почему разработчики решили обойтись без него.
В семерке тоже не было ООП. Некоторые умельцы реализовывали ООП с помощью внешних обработок. Мы пойдем другим путем – документированным.
Как говорится, если нельзя, но очень хочется, то можно.
Вы увидите, что основная парадигма ООП реализуется штатными средствами 1С 8.0.
Что такое объект в понятиях ООП?
Объект состоит из свойств и методов.
Объект может наследовать методы и свойства от другого объекта – предка.
Реализация в 1С 8
Для моделирования свойств объектов прекрасно подойдет объект типа «Структура», где можно хранить любые свойства любого типа.
Для реализации методов объектов будем использовать общие модули, по одному на каждый объект. В этих модулях будем описывать методы объекта в виде функций с именами ТипОбъекта_ИмяМетода. Хотелось бы конечно писать просто Об.ИмяМетода(Параметры), но придется писать примерно вот так: Метод(Об, ИмяМетода, Параметры).
Для передачи параметров опять же будем использовать только один параметр типа структура, который может содержать в себе любое количество параметров. К сожалению 1С не поддерживает вызов процедур с произвольным количеством и порядком вызова параметров.
Каждый объект содержит по ключу «Тип» название своего типа, для вызова соответствующего метода используется документированная функция «Выполнить».
Если метод не найден у объекта, он ищется у предка. Тип предка определяется через вызов у объекта метода Предок, если метод определен.
Если вызываемый метод не определен, система ничего не делает.
В методе можно вызвать метод предка, примерно так Предок(Об, ИмяМетода, Параметры).
Свойства можно назначать непосредственно, но для обеспечения контроля над свойствами лучше использовать функции Установить(Об, Свойство, Зн) и Получить(Об, Свойство).
Можно написать перехватчики событий установки-чтения свойств. Они носят имя ТипОбъекта_Установить и ТипОбъекта_Получить. Если ТипОбъекта_Установить возвращает истину, то свойство устанавливается, если ложь, то нет (этот обработчик может уже установить значения свойства и повторно его ставить не надо или запретить изменение свойства).
Конструктор объекта описывается в функции ТипОбъекта_Создать.
Деструктор объекта описывается в функции ТипОбъекта_Удалить. К сожалению, все вызовы деструкторов нужно вызывать явно, т.к. в 1С 8.0 нельзя отследить момент удаления локальной переменной.
Таким образом для реализации ООП достаточно 6 функций:
· Создать
· Метод
· Предок
· Установить
· Получить
· Удалить
Невероятно, но факт.
В принципе, объекты 1С 8.0 (документы, справочники и т.п.) можно рассматривать уже как готовые объекты. Действительно, у них можно получить тип. Кроме того, они обладают набором свойств. Таким образом, можно унифицировать работу с объектами через вышеуказанные шесть методов.
И если завтра вместо документа вы решите использовать справочник возможно в коде, ничего не придется менять.
Резюме.
Как я показал, ООП в 1С 8.0 можно реализовать легко и красиво, добавив только6 функций.
Зачем это нужно?
Некоторые библиотеки функций удобнее реализовать в виде библиотеки классов.
Например, списание по партиям удобно реализовать в виде объекта ОчередьПартий, а каждое из списаний по товарам, по долгам будет наследовать от базовой очереди, внося новые свойства.
Также можно реализовать библиотеки для работы с файлами, строками и т.п.
Единственно, нужно учитывать, что объектно-ориентированный подход в нашем случае нужно применять там, где прозрачность и понятность разработки важнее быстродействия, т.к. методы интерпретатора Выполнить все же медленнее скомпилированного кода 1С.
И все же, если в очередном релизе появится метод ВыполнитьФункцию(Имя Функции, Параметры), все ограничения по скорости будут сняты и ООП восторжествует. Видите, как для этого мало надо!
Кроме того, если использовать функцию Шаблон и вместо Структуры Список значений, то подобное ООП можно реализовать и в 7.7, правда вся реализация методов должна быть в одном глобальном модуле (в семерке нельзя реализовать несколько модулей).
Ну конечно бы хотелось, чтобы для всех 6 методов были введены операторы, но это уже от лукавого. Аминь!
Приложение.
Здесь я порекомендую разработчикам 1С 8.0 операторы для функций.
Создать = СоздатьОбъект ТипОбъекта
Метод = Об.Метод(Параметры)
Предок = Об::Метод(Параметры)
Установить = Об.Свойство=Зн;
Получить = Об.Свойство=Получить;
Удалить = УдалитьОбъект Об.
//Реализация объекта 1
Функция Объект1_Создать(Прм="")
КонецФункции
Функция Объект1_Печать(Я, Прм="")
Сообщить("Я объект 1");
Возврат 1;
КонецФункции
Функция Объект1_Известить(Я, Прм="")
Сообщить(Получить(Я, "Информация"));
Возврат 1;
КонецФункции
//Реализация объекта 2
Функция Объект2_Создать(Прм="")
КонецФункции
Функция Объект2_Предок(Я, Прм="")
Возврат "Объект1";
КонецФункции
Функция Объект2_Известить(Я, Прм="")
Сообщить("1С 8.0 - объектно-ориентированная среда!!! "+Прм);
КонецФункции
//Реализация объекта 3
Функция Объект3_Создать(Прм="")
КонецФункции
Функция Объект3_Предок(Я, Прм="")
Возврат "Объект2";
КонецФункции
Функция Объект3_Печать(Я, Прм="")
Сообщить("Я объект 3");
Предок(Я, "Известить", "Верите?");
Возврат 3;
КонецФункции
//// ФУНКЦИИ, РЕАЛИЗУЮЩИЕ ООП В 1С 8.0 /////
//Вызывает функцию, определенную в предке
Функция Предок(Об, Метод, Прм="", Сработал=ложь)
Перем Результат, Тип, Предок;
//Получаем тип объекта
Тип=Об.Тип;
Сработал=истина;
Попытка
Предок=Вычислить(Тип+"_Предок(Об, Прм)");
Попытка
Результат=Вычислить(Предок+"_"+Метод+"(Об, Прм)");
Возврат Результат;
Исключение
КонецПопытки;
Исключение
КонецПопытки;
Сработал=ложь;
Возврат Неопределено;
КонецФункции
Функция Метод(Об, Метод, Прм="", Сработал=ложь)
Перем Тип;
Сработал=истина;
//Получаем тип объекта
Тип=Об.Тип;
//Сначала пробуем просто вызвать метод самого объекта
Попытка
Возврат Вычислить(Тип+"_"+Метод+"(Об, Прм)");
Исключение
КонецПопытки;
Сработал=ложь;
//Затем пробуем вызвать метод у предка объекта
Возврат Предок(Об, Метод, Прм);
КонецФункции
//Создает объект
Функция Создать(Тип, Прм="")
Об=Новый Структура;
Об.Вставить("Тип",Тип);
Метод(Об, "Создать", Прм);
Возврат Об;
КонецФункции
Функция Установить(Об, Свойство, Зн)
Перем Сработал, Рез;
Прм=Новый Структура;
Прм.Вставить("Свойство", Свойство);
Прм.Вставить("Значение", Зн);
Рез=Метод(Об, "Установить", Прм, Сработал);
Если (Не Сработал) ИЛИ (Рез=Истина) Тогда
Об.Вставить(Свойство, Зн);
КонецЕсли;
Возврат Зн;
КонецФункции
Функция Получить(Об, Свойство)
Перем Сработал, Зн;
Прм=Новый Структура;
Прм.Вставить("Свойство", Свойство);
Зн=Метод(Об, "Получить", Прм, Сработал);
Если Не Сработал Тогда
Если Не Об.Свойство(Свойство, Зн) Тогда
Зн=Неопределено;
КонецЕсли;
КонецЕсли;
Возврат Зн;
КонецФункции
Процедура Сформировать(Элемент)
// Вставить содержимое обработчика.
Об1=Создать("Объект1");
Об2=Создать("Объект2");
Об3=Создать("Объект3");
Рез1=Метод(Об1, "Печать");
Рез2=Метод(Об2, "Печать");
Рез3=Метод(Об3, "Печать");
Сообщить("Результаты: "+Рез1+" "+Рез2+" "+Рез3);
Сообщить("Сначала информации нет:"+Получить(Об1, "Информация"));
Установить(Об1, "Информация", "Я храню некую информацию");
Сообщить("Потом мы ее устанавливаем:"+Получить(Об1, "Информация"));
КонецПроцедуры
Спасибо! Очень поучительно!
Я подумал было, что и впрямь объектно-ориентированный подход к эске кто придумал… 🙂
ООП создавалось не ради классов, наследований, перегрузки, конструкторов/деструкторов. Нет, — оно ставило задачи повторного использования кода и улучшения читаемости/сопровождаемости миллион-строчных программ. В те же годы предпринимались усилия для анализа и структурирования кода программ (открытые-закрытые члены, модель документ-представление и т.д). Криво спроектированная система классов (ООП) способна действовать в направлении, обратном вышесказанному. Хотя возможно будет радовать создателя — «могу же! ведь ООП же!»
А для чего? Стандартных классов, типа справочники, документы, перечисления — не хватает?
(4) Автор хороший пример привел — списание по партиям.
Вспомните, неужели у вас не было случаев, когда похожие (но таки разные!) алгоритмы использовались в разных местах? Да, можно это совместить в одну процедуру, которая будет менять своё поведение в зависимости от переданных параметров. Но намного удобнее сделать один класс со «стандартным» поведением, и несколько производных, с частично измененным.
(4) например, задача чтения из Эксель. Можно читать через OLE-объект, через ADO, через свои ВК. Но методы остаются одинаковыми.
(5) намного удобнее? ИМХО: вряд ли. Создание сущностей без их явной необходимости.
(6) Методы чего? Чтение через OLE и ADO отличаются и немало.
(7) отличаются в инициализации, но не в доступе к ячейке i,j
(7) Вопрос в том, насколько широкой должна быть возможность изменения поведения.
Целесообразность должна определяться конкретной задачей, нет «серебрянной пули» на все случаи.
(0)
Не факт. Я не знаю внутренностей метода «Выполнить», но следуя здравой логике — замедление не должно быть сколько-нибудь заметным. Ведь сам код находится внутри функции вызываемого метода, и никто не мешает выполнять его скомпилированным. Замедление будет только на этапе самого вызова функции, и то не факт.
Другое дело если передавать в «Выполнить» не имя функции, а сам программный текст — тогда да, замедление будет.
Плюс за то что заставляет 1С-программистов задумываться о том чего не хватает.
Лично мне ООП не хватает больше всего. Хоть и есть в 1С различные модули, но структурирование логики программы дается с большим трудом. А большинство вообще не забивают голову и превращают программы на 1С в мешанину функций и процедур.
удалить
какие-то классы надуманные.
Я бы начал с того, что создал класс, например, «счет10», — который умеет приходовать на этот счет, и списывать с него (при списании умееет посчитать остатки). Если надо — сделает это в налоговом плане счетов, если надо в бухгалтерском.
«Выше» идет класс «проводка10_60», который соединит «счет10» и «счет60″(умеет считать авансы). При создании (в конструкторе) они обменяются настроечной информацией (все ли поля заполнены и т.д.). Есть «проводкаНДС», котороый считает НДС.
Ещё «выше» — класс «документ» и.д. В принципе, класс «документ_ручная_проводка» должен быть базовым для всех «документов», но может вызываться самостоятельно.
Что-то из вышесказанного можно реализовать через «модуль менеджера».
(12) вы бредите. есть объект счет, он более универсальный чем счет 10 и счет 60.
Я что-то писал об «универсальности»?
О каком-таком «универсальном объекте счет» идет речть? Оба объекта «счет10» и «счет60» придумал пока я 🙂
«бредите…»
Не надо сильных слов, тем более при создании чего-то нового, неизведанного; тем более при «мозговом штурме».