1с что такое переопределяемый модуль
Переопределение общих модулей в условиях иерархии библиотек
Область применения: управляемое приложение, мобильное приложение, обычное приложение.
Методическая рекомендация (полезный совет)
При разработке нескольких библиотек, стоящих на поддержке друг у друга, следует минимизировать трудоемкость по обновлению кода переопределяемых общих модулей в каждой из библиотек. Для этого рекомендуется использовать следующую методику:
2. В библиотеках более высокого уровня реализация процедур и функций переопределяемого модуля базовой библиотеки может быть при необходимости доопределена. При этом в переопределяемом модуле размещается не сама реализация (ее код), а только один вызов.
Например, в общем модуле БазоваяБиблиотекаПереопределяемый в библиотеке верхнего уровня «Базовая библиотека» реализация фактически размещается в модуле МодульБазовойБиблиотеки :
Процедура НастроитьИнтерфейс(Знач ПараметрыРаботы) Экспорт
// Начало: Базовая библиотека
МодульБазовойБиблиотеки.НастроитьИнтерфейс(ПараметрыРаботы);
// Конец: Базовая библиотека
в этом же общем модуле БазоваяБиблиотекаПереопределяемый в следующей библиотеке верхнего уровня «Библиотека второго уровня»:
Процедура НастроитьИнтерфейс(Знач ПараметрыРаботы) Экспорт
// Начало: Базовая библиотека
МодульБазовойБиблиотеки.НастроитьИнтерфейс(ПараметрыРаботы);
// Конец: Базовая библиотека
// Начало: Библиотека второго уровня
МодульБиблиотекиВторогоУровня.НастроитьИнтерфейс(ПараметрыРаботы);
// Конец: Библиотека второго уровня
3. Таким образом, в конечной конфигурации-потребителе реализация переопределяемого модуля имеет вид:
Процедура НастроитьИнтерфейс(Знач ПараметрыРаботы) Экспорт
// Начало: Базовая библиотека
МодульБазовойБиблиотеки.НастроитьИнтерфейс(ПараметрыРаботы);
// Конец: Базовая библиотека
// Начало: Библиотека второго уровня
МодульБиблиотекиВторогоУровня.НастроитьИнтерфейс(ПараметрыРаботы);
// Конец: Библиотека второго уровня
Такой подход позволяет
Переопределяемые и поставляемые объекты библиотеки
Область применения: управляемое приложение, мобильное приложение, обычное приложение.
1. С точки зрения возможностей по настройке функциональности библиотеки для работы в конкретной конфигурации-потребителе все объекты библиотеки условно делятся на три категории:
2. Рекомендуется устанавливать для объектов этих категорий следующие правила поставки :
Эти рекомендации продиктованы следующими соображениями:
3. Для того чтобы упростить настройку библиотеки и снизить трудоемкость последующих обновлений версии библиотеки в конфигурации-потребителе следует минимизировать количество переопределяемых объектов с помощью следующих методик:
3.2. Переопределяемые общие модули должны содержать только экспортные процедуры, которые вызываются из кода самой библиотеки. Другими словами, не следует допускать вызовов процедур переопределяемых модулей непосредственно из кода конфигурации-потребителя.
Такое ограничение обусловлено соображением повышения устойчивости кода конфигурации, который вызывает библиотечные процедуры и функции, составляющие программный интерфейс библиотеки. К программному интерфейсу библиотеки следует относить только экспортные процедуры и функции непереопределяемых общих модулей.
Функция ПапкаФайлов(ВладелецФайловСсылка) Экспорт
СтандартнаяОбработка = Истина;
Результат = Неопределено;
ПапкиФайловПереопределяемый.ПриПолученииПапкиФайлов(ВладелецФайловСсылка, Результат, СтандартнаяОбработка);
3.3. При этом в переопределяемом модуле следует располагать только экспортные процедуры с пустой реализацией. В нем не должно быть каких-либо других не-экспортных процедур или функций. Базовую реализацию переопределяемых процедур и функций следует располагать в непереопределяемом коде.
Такое ограничение вызвано необходимостью снизить трудоемкость последующих обновлений переопределяемых модулей в конфигурации-потребителе.
Например, неправильно поставлять переопределяемый модуль МояБиблиотекаПереопределяемый с какой-либо реализацией:
Функция НастройкаПараметровРаботы() Экспорт
ПараметрыРаботы = Новый Структура;
// если настройки по умолчанию не подходят, то измените их.
ПараметрыРаботы.Вставить(«ПоказыватьЕдинственныйРаздел», Ложь);
ПараметрыРаботы.Вставить(«ЗадаватьДатуДляПрочихРазделов», Ложь);
ПараметрыРаботы.Вставить(«ИспользоватьВнешнихПользователей», Ложь);
Возврат ПараметрыРаботы;
а установку значений по умолчанию перенести в непереопределяемый общий модуль библиотеки:
ПараметрыРаботы = Новый Структура;
// настройки по умолчанию
ПараметрыРаботы.Вставить(«ПоказыватьЕдинственныйРаздел», Ложь);
ПараметрыРаботы.Вставить(«ЗадаватьДатуДляПрочихРазделов», Ложь);
ПараметрыРаботы.Вставить(«ИспользоватьВнешнихПользователей», Ложь);
// а теперь запросим конфигурацию-потребитель на случай,
// если эти умолчания не устраивают
МояБиблиотекаПереопределяемый.ПриПолученииНастроекПараметровРаботы(ПараметрыРаботы);
Возврат ПараметрыРаботы;
3.4. При обновлении версии библиотеки в конфигурации-потребителе особого внимания требуют модули корневого объекта конфигурации и переопределяемые общие модули, так как автоматическое обновление таких «узких мест» конфигурации-потребителя невозможно. Для настройки в конфигурации переопределяемых общих модулей рекомендуется придерживаться общего подхода:
Иерархия библиотек. Автоматическое обновление или как отказаться от переопределяемых модулей
Для разработки сложного программного обеспечения, фирма 1С рекомендует использовать библиотечный подход. Он описан, например, в Системе стандартов и методик разработки. Одной из особенностей этого подхода является использование в библиотеках переопределяемых модулей, содержимое которых должно быть изменено при внедрении библиотеки. Сами разработчики методики признают, что существует
. трудоемкость последующих обновлений переопределяемых модулей в конфигурации-потребителе.
При обновлении версии библиотеки в конфигурации-потребителе особого внимания требуют модули корневого объекта конфигурации и переопределяемые общие модули, так как автоматическое обновление таких «узких мест» конфигурации-потребителя невозможно.
А почему бы нам не сделать то, что кажется невозможным? Попробуем это на простом примере.
Итак, предположим нашей целью является автоматизация процесса продаж. Допустим, что в нашей системе должен быть документ «Продажа» с табличной частью «Товары», содержащей реквизиты «Номенклатура», «Цена», «Количество» и «Сумма». Базовым функционалом будет являться расчет
Этот расчет – функционал базовой библиотеки, которая будет лежать в основе остальных библиотек.
Возможно нам понадобится расчет налогов. Не вдаваясь в тонкости налогового учета, допустим что налог – это некая сумма, рассчитанная по ставке и просто добавляемая к основной сумме.
Аналогичным образом формализуем учет скидок:
Каждая из этих формул, а также объекты, содержащие все необходимые для расчета данные, реализованы в своей библиотеке. Но проблема в том, что запуск расчета производится в форме документа, в базовой библиотеке, в которой может быть ничего не известно о функционале, да и вообще о наличии других библиотек. Классический подход подразумевает реализацию в базовой библиотеке переопределяемого модуля расчета суммы, который в итоговой конфигурации должен быть дополнен (изменен) вызовами методов других библиотек.
Но можно поступить иначе. Предположим, в итоговой конфигурации у нас есть некий перечень методов, вызывая которые, мы сделаем все необходимые расчеты. Список этих методов может быть различным, в зависимости от конкретной конфигурации. Каждый метод реализован в модуле своей библиотеки. Все что нужно сделать при запуске расчета в базовой библиотеке – это передать такой перечень механизму, который обработает каждый элемент этого списка. Но где задать нам этот список методов? Опять использовать переопределяемый модуль и получить проблемы с обновлением? А пусть он создается сам, в зависимости от наличия той или иной библиотеки! Давайте придумаем некий механизм, который в зависимости от наличия каких-нибудь объектов метаданных, поймет, какие методы каких модулей надо включить в список для выполнения расчета. Здесь появляется небольшая проблема: для поиска среди объектов метаданных можно использовать только имя, а объекты одного вида с одинаковым именем создавать нельзя. Т.е. нельзя в каждой библиотеке создать свой общий модуль с именем «РасчетСуммы» и объединить их в одну конфигурацию. Но можно создавать подсистемы с одинаковыми именами, если они принадлежат разным родителям. Получается следующая схема:
Для каждой библиотеки создана своя подсистема, в которой есть подсистема с именем «РасчетСумм«. В составе последних включены общие модули, в которых реализован экспортный метод, выполняющий расчет (имена методов также одинаковы). Подсистемы библиотек лежат в пределах одной группы, для упрощения поиска. Таким образом, ориентируясь на имя подсистем «РасчетСумм» мы легко можем получить список модулей и методов для проведения расчета.
Несколько слов по поводу выполнения этих методов. Самый простой вариант – создание некоего «менеджера», который будет последовательно вызывать каждую процедуру. Но я решил остановиться на другом способе – вызывать самую последнюю процедуру из списка и передавать ей управление. Решение о вызове предыдущего метода полностью возлагается на эту процедуру. Такой вариант более гибок – предыдущий метод может быть вызван в любом месте, а может и быть просто проигнорирован, если в нем нет нужды. Порядок методов в списке определяется порядком расположения подсистем библиотек внутри «ПереопределяемыеОбъектыБиблиотек«.
Как это выглядит на практике:
В документе «Продажа» реализована команда:
В серверной процедуре получаем последовательность описаний методов и запускаем выполнение последнего из них. В нашем случае это будет РасчетСуммСоСкидкой.РасчетСумм
В процессе расчета мы сначала выполняем предыдущий метод РасчетСуммСНалогом.РасчетСумм, а затем производим обработку скидки.
Перед налоговым расчетом мы так же вызываем предыдущий метод РасчетСуммБазовый.РасчетСумм:
В котором выполняем самый первый расчет.
в последнем случае метод УправлениеБиблиотеками.ВыполнитьПредыдущуюПроцедуруНаСервере не выполнит ничего, так как предыдущих процедур не осталось.
Описанный выше механизм можно применять и для других целей, например для создания общего списка строковых или табличных ресурсов. Вот так реализовано описание конфигурации, которое создается на основе табличных макетов, принадлежащих разным библиотекам:
В обработке «Инфо» создается общий табличный документ:
Как внедрять или обновлять получившиеся библиотеки.
Процесс внедрения и обновления библиотек – обычное сравнение объединение конфигураций. В этом режиме надо отметить объекты по подсистемам файла:
и выполнить объединение. При этом никаких других действий, таких как редактирования модулей, делать не надо.
Подобное объединение можно проводить в автоматическом режиме. Для этого служит специальная команда пакетного режима конфигуратора. Пример такой команды:
здесь мы указываем, что не меняем свойства конфигурации, разрешаем удалять объекты, помечаем для объединения объекты нужных нам подсистем. Обратите внимание, что каждую подсистему мы указываем дважды: в новой конфигурации (для добавленных и измененных объектов) и в основной конфигурации (для измененных и удаленных объектов).
В результате обновления мы получим итоговую конфигурацию, в которой может быть (а может и не быть) одна или две библиотеки. Существуют несложные средства, которые позволят нам так же автоматически поместить эти изменения в хранилище 1С или же в Git.
Итак, вот что мы получили: базовую библиотеку и две дополнительные библиотеки, на основе которых можем в автоматическом режиме собрать четыре разные конфигурации для разных заказчиков. Эти конфигурации различаются по функциональным возможностям и могут иметь разную продажную стоимость, что позволит более гибко составлять коммерческие предложения.
Рассмотренный пример вы можете увидеть в приложенном к статье файле. Это архив, содержащий в себе:
Желательно чтобы все эти папки и файлы находились в каталоге c:\bases, так как в пакетных файлах используются абсолютные пути. Также надо указать путь к файлу 1cv8.exe в зависимости от версии платформы.