Перейти к основному содержимому

Контракт

Контракты — это элементы проекта, которые описывают (но не реализуют) набор свойств и методов (или только набор методов). Существует три вида контрактов:

Реализация свойств и методов, объявленных в контракте, находится в некотором элементе проекта. В этом случае говорят, что этот элемент проекта реализует данный контракт (подробнее).

Грубо говоря, контракт описывает то, какие свойства и методы есть у элемента, который реализует этот контракт.

Контракты позволяют воплощать следующие парадигмы разработки:

  • Полиморфизм. Могут существовать разные элементы проекта, реализующие контракт, но все они имеют набор одинаковых свойств и методов. Это те свойства и методы, которые объявлены в контракте. Поэтому вы можете одинаковым образом обращаться к данным разных элементов проекта, реализующих один и тот же контракт.
  • Инкапсуляция. Контракт можно использовать для того, чтобы скрыть от других частей проекта реализацию некоторой части бизнес-логики. Вы можете объявить в контракте набор методов, которыми должны пользоваться другие части приложения, если им нужно получить данные из вашей подсистемы. Реализацию этих методов вы можете изменять от версии к версии, при этом остальная часть проекта не будет изменяться, т. к. она использует методы, объявленные в контракте.
  • Множественная реализация. Один элемент проекта может реализовывать несколько контрактов.

Значения по умолчанию в методах контрактов

Значения по умолчанию можно указывать только в методах контрактов. В методах, которые реализуют (@Реализация) или переопределяют (@Переопределение) методы контракта, указывать значения по умолчанию запрещается для всех параметров. При этом при вызове метода и через тип-реализацию, и через тип контракта значения по умолчанию берутся из контракта.

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

Наследование контрактов

Для контракта можно задать базовые пользовательские контракты. В этом случае он будет иметь:

  • собственные свойства и методы,
  • свойства и методы из базовых контрактов.

Например, пусть есть библиотека Рассылки, в которой описан контракт сущности ПолучательСообщений. Вы разрабатываете библиотеку Форум и добавляете в нее контракт сущности УчастникФорума. Чтобы показать, что участник форума также является получателем сообщений, вы указываете контракт ПолучательСообщений в качестве базового для контракта УчастникФорума.

Чтобы задать базовые контракты, используется специальное свойство контракта:

Если в текущем и базовом контрактах указаны свойства с одинаковыми именами, то в зависимости от признака ТолькоЧтение возможны следующие варианты:

  • если ТолькоЧтение = Ложь как в базовом, так и в текущем контракте, то тип свойств должен совпадать;

  • если в базовом контракте ТолькоЧтение = Истина, то независимо от значения признака в текущем контракте тип свойства может быть следующим:

    • для ссылочных типов может быть более конкретным (например, в базовом контракте — <ИмяКонтракта>.Ссылка, а в наследуемом — <ИмяСправочника.Ссылка>);

    • для составных типов может быть подмножеством типа свойства из базового контракта (например, в контракте — тип Строка | Число, а в реализации — Число);

    • в остальных случаях должен точно соответствовать типу в базовом контракте;

      Ограничения свойств в контрактах сущности

      Если в базовом контракте сущности свойства имеют ограничения значений, то ограничения в текущем контракте могут быть строже (подробнее).

  • если в базовом контракте ТолькоЧтение = Ложь, то в текущем контракте признак не может иметь значение Истина.

Если в текущем и базовом контрактах указаны методы с одинаковыми именами, то в текущем контракте метод должен быть помечен аннотацией @Переопределение:

Пример переопределения метода в текущем контракте
@Переопределение
абстрактный метод Оповестить()

Примеры