Миксины и трейты#

В разделе описаны механизмы наследования классов сущностей с помощью миксинов и трейтов, их создание, подключение, кодогенерация и особенности использования.

Механизмы наследования#

Фреймворк не поддерживает полноценное классическое наследование классов сущностей. Понятие «наследование» используется для описания логической связи двух классов.

Вместо классического наследования фреймворк использует миксины и трейты.

Миксин (Mixin)#

Миксин (англ. mix-in) — это элемент языка программирования, обычно класс или модуль, реализующий чётко выделенное поведение. Миксин используется для уточнения поведения других классов и не предназначен для самостоятельного создания объектов.

В системе Global3 Postgres миксин — это специализированный класс, каждый объект (запись в таблице) которого соответствует одному объекту подключённого класса (записи в основной таблице). Миксин-класс может быть подключён к неограниченному числу других классов.

Для объектов миксина первичным ключом является поле gidRef. Его значение автоматически устанавливается равным значению поля gid объекта подключённого класса в момент создания.

В API миксина реализуются общие методы, доступные для всех подключённых классов.

Миксин может содержать произвольное число атрибутов. Если имя атрибута миксина совпадает с именем атрибута подключённого класса или его наследника, значение синхронизируется автоматически.

Примечание

Все Scala-классы, соответствующие миксину, наследуются от системных классов D-ветви и имеют префикс D. Остальные Scala-классы, соответствующие обычным сущностям, наследуются от системных классов S-ветви и имеют префикс S.

Для миксинов метод получения Rop по gidRef называется loadByGid. Также реализован метод, аналогичный методу get для SApi:

getByGid(gidpRef: NGid): Option[ApiRop]

Системные миксины#

Системные миксины функционально не отличаются от прикладных. Основной системный миксин — Btk_Object.

При формировании кода для классов с supertype="document" и supertype="reference" этот миксин автоматически подключается к классу. Миксин обеспечивает базовую инфраструктурную функциональность: корректную работу версионирования, аудита изменений и синхронизации данных.

Миксин Btk_Object можно отключить с помощью свойства в ODM-файле:

<reflection isEnabled="false"/>

Пример см. в классе Btk_Group.

Прикладные миксины#

Все остальные миксины, например bs_settler, создаются разработчиками вручную для решения конкретных прикладных задач и не являются частью системной функциональности.

Создание класса-миксина#

В ODM-файле необходимо объявить атрибут gidRef:

<attr name="gidRef" attribute-type="Varchar"/>

Для класса необходимо указать свойство supertype="mixin":

<class xmlns="http://www.global-system.ru/xsd/global3-class-1.0"
      name="Xxx_ClassName" supertype="mixin"/>

Формирование кода#

При формировании кода для класса-миксина Dpi наследуется от MixinApi:

trait Xxx_XxxxDpi[T] extends MixinApi[java.lang.Long, ARO, API]

Dvi наследуется от AppMixinAvi:

trait Xxx_XxxDvi extends AppMixinAvi

Основные методы для работы:

//создание по rop мастера, возвращает rop миксина
Api().insertByParent(ropMaster)
//загрузка миксина по gidRef, возвращает rop миксина
Api().loadByGid(gidRef)
//удаления по gidRef
Api().deleteByKey(gidRef)

Объявление подключённых классов#

Для связывания класса с миксином необходимо в ODM-файле указать имена классов-миксинов:

<mixins>
  <mixin name="Bs_Settler" isDpiManaged="true"/>
</mixins>

При формировании кода сущности в Dpi добавляется код:

  • вставки объекта миксина в методе insert;

  • удаления объекта миксина в методе delete;

  • установки значений атрибутов миксина. Код добавляется в сеттеры атрибутов сущности, имена которых совпадают с именами атрибутов миксина.

Для ручного управления генерацией миксина необходимо отключить формирование кода в Dpi с помощью настройки isDpiManaged.

По умолчанию для всех подключённых миксинов генерируется код в Dpi.

Ссылочность на миксин#

Для атрибутов, ссылающихся на миксин, необходимо указывать тип refAnyObject:

<attr name="gidSettler"
      attribute-type="Varchar"
      caption="Контрагент"
      type="refAnyObject"
      isVisible="false"
      order="20"
      ref.class="Bs_Settler"/>

Для автоматической генерации атрибутов HL (Head Line) и MC (Mnemo Code), сеттеров этих атрибутов и добавления их в selectStatement и onRefreshExt необходимо указать в настройке ref.class класс миксина для ссылки.

Важно

Для миксинов по ссылочным атрибутам не генерируются внешние ключи. Вместо них генерируются индексы.

Трейт (Trait)#

Трейт — это механизм повторного использования кода между классами. В отличие от наследования класс может содержать несколько трейтов. Трейт не имеет объектов, собственной структуры хранения данных и визуального представления.

Чтобы создать трейт:

  1. Создайте ODM-файл.

  2. Укажите свойство supertype="trait".

При формировании кода создаются только файлы Dpi и Api. Dpi содержит только объявления сеттеров и геттеров.

Наследование сущности от трейта#

Для наследования сущности от трейта добавьте в ODM свойство класса with="Trait_Name".

Сущность, наследуемая от трейта, должна иметь все атрибуты, объявленные в трейте.

Перекрытие и порядок вызовов методов#

Рассмотрим код трейта и наследуемого от него класса:

trait Gs3_TraitApi[T] extends Gs3_TraitDpi[T] {
  override def setFNumber(rop: ApiRop, value: NNumber): Unit = {
    Logger.Factory.get(getClass).info("Gs3_TraitApi.setFNumber")
    super.setFNumber(rop, value)
  }
}

class Gs3_DescendantApi extends Gs3_DescendantDpi[T] with Gs3_TraitApi[T] {
  override def setFNumber(rop: ApiRop, value: NNumber): Unit = {
    Logger.Factory.get(getClass).info("Gs3_DescendantApi.setFNumber")
    super.setFNumber(rop, value)
  }
}

В результате выполнения метода Gs3_DescendantApi.setFNumber() последовательность вызовов будет следующей:

  1. Gs3_DescendantApi.setFNumber.

  2. Gs3_TraitApi.setFNumber.

  3. Gs3_DescendantDpi.setFNumber.