Подпрограммы, функциональная абстракция, скрытие информации
8.4 Анатомия объявления метода
Объявление show_station задает типичную форму метода. Многие из его элементов нам уже хорошо знакомы.
Метод является программным элементом, задающим множество операций, которые должны быть выполнены по требованию других программных элементов, называемых вызовами метода. Пока у нас есть один пример вызова show_station — цикл, в котором есть вызов:
show_station (Line8.item)
Такой вызов обычно появляется в методе; здесь мы предполагаем, что вызов встроен в метод traverse того же класса ROUTES. В таких случаях говорят, что метод traverse является вызывающим методом (вызывателем — caller) метода show_station.
Если метод класса C вызывает метод класса S, то это делает класс C клиентом класса S. В данном случае класс ROUTES становится своим собственным клиентом.
Во всей системе (программе) метод может быть целью одного, многих или ни одного вызова, но он всегда имеет единственное появляющееся в классе объявление, которое определяет алгоритм метода. Давайте проанализируем ранее приведенное объявление метода show_station. Вот его первая строка:
show_station (s: STATION)
Она задает имя метода и его сигнатуру: список его формальных аргументов, если они есть, и их типы. Формальные аргументы представляют значения, которыми оперирует метод. Каждый вызыватель в момент вызова передает свои значения через фактические аргументы, соответствующие формальным аргументам.
Фактические аргументы являются выражениями, тип которых должен соответствовать формальным аргументам.
Данное ранее определение аргумента соответствует как формальному, так и фактическому аргументу.
Сигнатура метода show_station включает один формальный аргумент — s типа STATION. В примере его вызова фактическим аргументом является Line8.item. Тип этого выражения действительно принадлежит STATION, так как запрос item класса LINE возвращает станцию в качестве результата. Если же типы несовместимы, то EiffelStudio выдаст сообщение об ошибке на этапе компиляции системы:
В этом примере мы передаем фактический аргумент произвольного типа WRONG_TYPE при вызове метода show_station, чей формальный аргумент имеет тип METRO_STATION. Сообщение об ошибке объясняет, что сделано неверно.
В теле метода show_station мы используем формальный аргумент s как значение, обозначающее станцию. Операция, применяемая к s, при любом вызове будет выполняться над фактическим аргументом: в нашем примере — над станцией, заданной Line8.item.
Не все методы имеют аргументы - примером является метод remove_all_segments.
Оставшаяся часть объявления show_station содержит следующие элементы.
- Метод должен иметь заголовочный комментарий, объясняющий, что он делает. В примере "— Подсветить s в форме, согласованной со статусом" стиль требует комментировать все формальные аргументы (здесь s), указывая роль каждого аргумента. Следует избегать избыточности (скажите "s", но не "станция "s"", поскольку предыдущая строка объявляет s: STATION).
- Предусловие, здесь s /= Void, устанавливает, что работа возможна только с присоединенными фактическими аргументами.
- Предложение do, называемое телом метода, состоит из последовательности операторов, задающих алгоритм, реализуемый методом.
- Хотя в примере не появилось постусловие, но оно является возможной частью метода.
Интерфейс и реализация
В EiffelStudio можно видеть как реализацию, так и интерфейс метода, такого как show_station.
- Реализация (объявление) появляется в облике класса по умолчанию, известном как "текстовый облик". Это полное объявление метода.
- Интерфейс появляется по запросу "контрактного облика" при нажатии соответствующей кнопки. С его формой мы уже познакомились, когда изучали интерфейс методов класса LINE.
show_station (s: STATION) — Подсветить s в форме, согласованной со статусом. require station_exists: s /= Void
Интерфейс метода адресован программистам, создающим клиентские классы. Из выше перечисленных элементов метода интерфейс содержит: сигнатуру, заголовочный комментарий, предусловие и постусловие, но не показывает тело метода, деталей реализации. Интерфейс метода должен говорить, что метод делает, но не как он это делает. Сигнатура и контракты, дополненные поясняющим комментарием, достаточны, чтобы выразить "что".
Контрактный облик класса отличается от текстового тем, что опускаются некоторые детали синтаксиса - ключевое слово end, необходимое в программах во избежание двусмысленности, но не требуемое в описании интерфейса.
8.5. Скрытие информации
Прием, когда программисту — клиенту метода (класса, любого другого модуля) — предоставляется описание интерфейса, включающего лишь подмножество свойств программного элемента, называется скрытием информации.
Скрытие информации — один из ключевых инструментов, позволяющих строить большие программные системы и успешно бороться с их сложностью: предоставлять клиентам каждого элемента только то, что нужно для его использования.
Несмотря на название, скрытие информации не означает запрет на знакомство с реализацией, так как Traffic и другие Eiffel библиотеки доступны в исходной форме. В EiffelStudio нетрудно познакомиться со всеми методами класса LINE и других Traffic-классов. Скрытие информации исходит из того, что для использования элемента не требуется знание его реализации.
Если для каждого используемого метода пришлось бы читать полный его текст, то количество информации превзошло бы все разумные пределы. Скрытие информации позволяет нам ограничиться лишь небольшой частью, и это наш лучший друг в постоянной борьбе со сложностью.
Не все библиотеки дают доступ к исходному коду, скрывая свои ноу-хау. Скрытие информации - это технический прием, не связанный с экономическими или политическими решениями, это лишь способ защиты от груды не относящихся к делу деталей.
Скрытие информации — это оружие не только в борьбе со сложностью, но и с нестабильностью. Одно из главных свойств ПО — способность гибких изменений, — недаром его называют софтом. Всякое изменение программного элемента сказывается на его клиентах, у которых также есть клиенты, что может включать целую цепь изменений. Но для хорошо спроектированных элементов с тщательным отбором того, что составляет интерфейс элемента, многие изменения могут быть связаны только с реализацией, не затрагивая интерфейс, а, следовательно, не влияя на клиентов. Это дает неоценимый инструмент для управления программными проектами.
Современная ОО-технология с наследованием и динамическим связыванием делает следующий шаг в скрытии информации, позволяя клиентам не только не вникать в детали применяемых к объектам операций, но и не знать точные типы этих объектов. Но до этого этапа предстоит еще дойти, а пока ограничимся скрытием реализации методов.