@Michaellux

Проектирование по контракту. Это для повторного использования или для корректности ПО?

Начало

Сейчас я заново открываю для себя ООП. Если раньше смотрел через призму конкретного языка программирования, то теперь разбираюсь откуда вообще взялось ООП, понятия абстракции, инкапсуляции, наследования; для чего оно нужно и можно ли без этого обойтись.

Дошёл до понятий абстрактного класса и интерфейса. Если забить в поисковике "для чего нужны абстрактные классы" или "для чего нужны интерфейсы", то он выдаст посты примерно с таким обоснованием для их применения: "для работы иногда вам требуются ", "он может пригодиться, если". Воспринимается как нечто необязательное.

Для чего они нужны в ООП в принципе (в широком смысле), а не в конкретном языке программирования я не понял.
Поэтому обратился к книгам.

Середина

Я читаю несколько книг параллельно, но упоминать я буду следующие:

1. "Объектно-ориентированное мышление" М. Вайсфельда
2. "Объектно-ориентированный анализ и проектирование с примерами приложений" Г. Буча
3. "Программист-прагматик. Путь от подмастерья к мастеру" Э. Ханта, Д. Томаса

Возьмём Вайсфельда. Упоминание о том, для чего нужны абстрактные классы и интерфейсы мы находим в начале 8 главы.

5d53a587b7856833160449.png

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


То есть, грубо говоря, интерфейсы и абстрактные классы обеспечивают "reusabiity" ПО.

Я вспомнил, что сочетание "контрактная модель" мне уже встречалась у Буча:

5d53a84e60580330165993.png
5d53bbca1ae17484658107.png

При прочтении создаётся впечатление, что контрактная модель имеет более глобальное значение. Чуть ли не основа основ.

У меня начали появляться мысли, что, возможно, абстрактные классы и интерфейсы и описывают, что должен делать объект, что они и есть часть того самого контракта. Это и есть воплощение идеи ответственности/обязанности объекта в языках программирования.

Чтобы в этом удостовериться, обратился к первоисточнику - к книгам Бертрана Мейера в котором описана технология "проектирования по контракту". На первый взгляд, судя по определению всё сходилось:

Проектирование по контракту (Design by Contract) - установление отношений между классом и его клиентами в виде формального соглашения, недвусмысленно устанавливающее права и обязанности сторон.


Но чем дольше я читал, тем больше убеждался, что Вайсфельд и Буч слишком вольно трактуют понятие контракта, либо имеют ввиду какой-то свой "контракт".

Поскольку у Вайсфельда концепция контрактов обеспечивает повторное использование ПО,
у Ханта и Томаса это средство защиты от ошибок:

5d53b2cb8d160472573133.png

А у Мейера это средство построения надёжного ПО:

5d53b23d1825c460587239.png

Кроме того, определение инварианта, постусловия и предусловия у Мейера и у других авторов разительно отличаются.

Конец

Возникает множество вопросов.

Можно ли считать Мейера предтечей идеи что класс - это и есть контракт, состоящий из интерфейса и реализации?
Является ли проектирование по контракту основой основ или это всего-навсего один из подходов к разработке ПО?
Имеет ли место вольная трактовка понятий контракта, предусловия, постусловия, инварианта?
Можно ли, например, считать, что предусловия - это те самые интерфейсы, которые должны быть реализованы, чтобы программа выполнилась?
  • Вопрос задан
  • 427 просмотров
Пригласить эксперта
Ответы на вопрос 3
dmitriylanets
@dmitriylanets
веб-разработчик
Прочитайте книгу "Чистая архитектура" (Р.Мартин), все встанет на свои места.
Контракт - не может быть реализацией, это абстракция. Применяется тогда когда планируется менять реализацию (конкретику) контракта по мере эксплуатации системы, обычно в долгоиграющий проектах.

Абстрактный класс - это родительский класс который дает своим предкам что то общее + необходимость реализации своего контракта, но он относится к конкретике, а не контракту.
Ответ написан
begemot_sun
@begemot_sun
Программист в душе.
Когда вы делаете ПО вы делаете код который взаимодействует с другим кодом.
Любая функция, процедура, каждая строка --- это код который взаимодействует с другим кодом выше или ниже по тексту. Взаимодействие одного кода с другим кодом всегда осуществляется через некий интерфейс -- набор правил входа\выхода и ожиданий в поведении кода. Даже когда вы объявляете переменную в локальной области видимости - это тоже интерфейс для кода, который использует эту переменную. Другой код ожидает, что в переменная существует, имеет корректное значение, и может быть использована корректным образом. Каждый раз эти правила сосуществования кода различны, они меняются от языка к языку от разработчика к разработчику.
Лучший язык (моё имхо) - это тот язык который подходит для описания интерфейсов взаимодействия в широком смысле этого слова. Я говорю об интерфейсе как некотором контракте одного кода с другим, одной строки кода со следующей, одного оператора с другими.
Конечно существуют разные подходы для описания таких интерфейсов. Сейчас распространен принцип описательного "делай как я сказал". В этом подходе программа дробиться на простые сущности, которые каким-либо образом взаимодействуют друг с другом.
В ООП это классы-объекты, в функциональном - это функции.
Суть меняется на самом деле слабо, все это нужно чтобы:
1. формализовать описание интерфейсов взаимодействия.
2. Прийти к какому-то единообразному способу такого описания.

В ООП идут дальше, абстрагируясь от конкретной реализации класса, и вводя лишь только способы взаимодействия сущностей (описание этого взаимодействия). Т.о. появляется абстрактные классы и интерфейсы.
В функциональном способе описания также пошли в сторону абстракции. Например а Haskell есть типы и интерфейсы типов -- это что касается контрактов, и есть функции высших порядков -- это что касается реализации интерфейсов.
Такими способами уменьшается сложность ПО и дробиться код улучшается надежность.
Но даже жесткий линейный код на BASIC - это все тот же способ описать интерфейс взаимодействия одного кода с другим.

Помимо ООП и функционального программирования есть куча других методик:
Полный список можно тут взять: https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%82%D... - и тот достаточно абстрактно-сырой.

Короче ООП это не панацея, а лишь еще один способ описания этого дивного и сложного мира и взаимоотношений в нем.
Ответ написан
Комментировать
Adamos
@Adamos
Контракт, как я понимаю этот термин - это то, что весь прочий код (а также те, кто использует его позже) должны знать о конкретном коде для взаимодействия с ним. В ООП в этой роли традиционно выступает публичный интерфейс класса.
Абстрактные же классы и интерфейсы позволяют всему прочему коду ничего не знать о целой иерархии классов, которые наследуют эти абстракции. Внешние связи кода сужаются до минимума. И с точки зрения уменьшения сложности, тестирования (да и вообще понимания, что происходит в коде) это, конечно, очень большой плюс.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы