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

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

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

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

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

### Миксин (Mixin)

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

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

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

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

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

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

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

```scala
getByGid(gidpRef: NGid): Option[ApiRop]
```

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

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

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

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

```xml
<reflection isEnabled="false"/>
```

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

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

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

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

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

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

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

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

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

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

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

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

```scala
trait Xxx_XxxDvi extends AppMixinAvi
```

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

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

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

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

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

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

- вставки объекта миксина в методе `insert`;
- удаления объекта миксина в методе `delete`;
- установки значений атрибутов миксина. Код добавляется в сеттеры атрибутов сущности, имена которых совпадают с именами атрибутов миксина.

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

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

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

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

```xml
<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` класс миксина для ссылки.

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

### Трейт (Trait)

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

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

1. Создайте ODM-файл.
2. Укажите свойство `supertype="trait"`.

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

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

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

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

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

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

```scala
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`.
