Перейти к содержанию

Liskov Substitution Principle (LSP)

LSP требует, чтобы одну реализацию можно было заменить другой без поломки ожиданий клиента.

Что означает в 1С

Если модуль или объект объявлен как реализация общего контракта, клиент должен иметь возможность работать с ним одинаково:

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

Пример на 1С

Function Load(Source) Export

    Return Source.GetRows();

EndFunction
Function GetRows() Export

    Return New ValueTable;

EndFunction
Function GetRows() Export

    Raise "Can be used only from form";

EndFunction

InteractiveOnlySource формально похож на подходящую реализацию, но фактически нарушает LSP: клиент ожидает, что GetRows() можно вызвать по контракту, а получает ограничение, о котором контракт ничего не сказал.

Типичный пример в 1С

В 1С нарушение LSP часто проявляется не только в возвращаемых значениях, но и в способе сигнализации об ошибках.

Например, для сценария проверки заполнения обычно ожидается, что обработчик:

  • установит Отказ = Истина;
  • добавит понятные сообщения пользователю;
  • завершит проверку без исключения.

Именно на такой стиль работы завязаны и платформа, и рекомендации по #std400: Проверки, выполняемые в форме, и по #std463: Проверки, выполняемые в и вне транзакции записи объекта.

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

Условно:

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)

    Если Не ЗначениеЗаполнено(Контрагент) Тогда
        Сообщение = Новый СообщениеПользователю;
        Сообщение.Текст = "Не заполнен контрагент.";
        Сообщение.Сообщить();
        Отказ = Истина;
        Возврат;
    КонецЕсли;

КонецПроцедуры

И проблемный вариант:

Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)

    Если Не ЗначениеЗаполнено(Контрагент) Тогда
        ВызватьИсключение "Не заполнен контрагент";
    КонецЕсли;

КонецПроцедуры

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

Где полезен

  • в семействах взаимозаменяемых сервисов;
  • в расширяемых точках конфигурации;
  • там, где один и тот же клиент работает с несколькими реализациями.

Когда применяют неправильно

  • когда общий контракт слишком расплывчат;
  • когда разные реализации на самом деле решают разные задачи;
  • когда ограничения реализации не выражены в контракте.