Как происходит отслеживание свободного экстента? |
Подпрограммы, функциональная абстракция, скрытие информации
Время программирования!
При нажатии кнопки "Compile" EiffelStudio не компилирует всю систему заново, что могло требовать большого времени: компилируются только те классы, которые были модифицированы после последней компиляции, и те, которые прямо или косвенно зависят от них. Это называется нарастающей (incremental) компиляцией. В студии она выполняется автоматически, нет необходимости в указании модифицированных классов, в указании зависимостей между классами.
Скрытие информации является основой анализа зависимостей: если вы изменили только реализацию, EiffelStudio обнаружит это и не будет перекомпилировать клиентские классы. Если же изменения затронули интерфейс, то придется перекомпилировать и клиентов. Вы можете следить за этим процессом.
- Добавьте метод r в класс LINE. Не важно, что делает этот метод, пусть лишь у него будет аргумент и предусловие.
- В методе traverse из класса ROUTES добавьте вызов r. Убедитесь, что вызов корректен, - он должен при вызове задавать фактический аргумент требуемого типа.
- Перекомпилируйте систему. Заметьте, какие классы были скомпилированы заново (для просмотра результатов компиляции выберите вкладку "Output").
- Внесите изменения в тело r, не изменяя его интерфейс. Перекомпилируйте, наблюдая за процессом компиляции.
- Теперь добавьте предложение постусловия в r, что изменяет его интерфейс. Перекомпилируйте, проследив за процессом компиляции ROUTES.
- Для возвращения системы в первоначальное состояние удалите r из LINE и вызов r из traverse. Перекомпилируйте и убедитесь, что все работает должным образом.
8.6. Процедуры против функций
Есть два вида методов:
- Процедура: выполняет некоторые действия. Вызов процедуры в вызывающем методе является оператором. Методы traverse и show_station являются примерами процедур. К процедурам относятся и изучаемые ранее процедуры создания, служащие для создания и инициализации объектов класса.
- Функция: вычисляет некоторое значение. Вызов функции в вызывающем методе представляет выражение. С реализацией функций нам пока не пришлось встретиться, но вызывать функции приходилось: запрос i_th в классе LINE является функцией.
Разница известна:
- процедура реализует команду;
- функция реализует запрос.
Команды могут быть реализованы только процедурами, но запросы могут быть реализованы как функциями, так и атрибутами, о чем пойдет разговор в следующей лекции.
Мы видели, что сигнатура процедуры характеризуется списком типов формальных аргументов, как при объявлении метода show_station:
show_station (s: STATION)
Сигнатура функции дополнительно должна указывать тип значения, возвращаемого функцией. Это можно видеть на примере запроса i_th в LINE, возвращающего результат типа STATION:
i_th (i: INTEGER):STATION
Оставшаяся часть объявления функции имеет те же элементы, что и процедура: заголовочный комментарий, предусловие, постусловие, тело. В теле функции и в постусловии необходимо имя для именования результата, возвращаемого функцией, — для него зарезервировано специальное ключевое слово Result.
8.7. Функциональная абстракция
Методы являются базисными алгоритмическими блоками, входящими в наши классы, а через них и в системы.
Используйте методы как механизм алгоритмической абстракции. Абстракция означает концентрацию на сущности, а не на деталях, на общих концепциях, а не на отдельных примерах. Абстракция почти всегда влечет именование. Как только выделена полезная абстракция, дайте ей имя, что позволит ссылаться на нее в будущем. В программировании мы встречаемся с двумя полезными видами абстракций.
- Абстракцией данных, которую дает нам класс, представляющий описание данных программы — объектов.
- Абстракцию алгоритмов, называемую также функциональной абстракцией, которая позволяет описать абстракцию, стоящую за нашими алгоритмами.
Для сохранения управляемости системой, даже в тех случаях, когда алгоритмы включают много деталей, используются методы. Оба подхода при проектировании метода "сверху вниз" и "снизу вверх" представляются привлекательными.
- Создав алгоритмический элемент, покрывающий важный шаг процесса разработки, превратите его в метод. Тогда у него появится имя и точная спецификация (сигнатура, заголовочный комментарий и контракт). Это превратит его, наряду с другими преимуществами, в хорошо определенный программный элемент, допускающий повторное использование. Это соответствует подходу "снизу вверх".
- При разработке "сверху вниз" в процессе разработки идентифицируется метод, детализация которого временно не выполняется, что позволяет сосредоточиться на достижении главной цели.
В этой второй роли альтернативой методу может быть псевдокод. Мы встречались с использованием псевдокода в наших примерах:
— "Создать линию и заполнить ее станциями"
Псевдокод можно заменить методом, называемым "заглушкой" или держателем места. В
этом случае систему можно скомпилировать, поскольку достаточно существования метода, даже если он ничего не делает. Вот пример:
create_fancy_line - Создать фиктивную линию fancy_line и заполнить ее станциями do - Здесь следует указать (ваше имя, текущую дату) ensure line_exists: fancy_line /= Void end
Обратите внимание, постусловие задает часть контракта: метод должен создать объект и связать его с fancy_line.
Почувствуй методологию
Если вы используете заглушку, всегда включайте в нее информацию о себе и о дате создания, а также заголовочный комментарий и другие пояснения того, что вы собираетесь позднее делать. Если для метода можно задать контракт (предусловие и постусловие), то напишите его сразу, включив в заглушку. Контракт, являясь частью спецификации метода, позволяет понять, что нужно делать, и будет служить руководством, когда вы вернетесь к детализации метода, превращая заглушку в настоящий метод.
8.8. Использование методов
Методы — алгоритмические абстракции — лучшее средство в борьбе со сложностью. Используйте их при разработках "снизу вверх", подготавливая существующие элементы для дальнейшего повторного использования. Используйте их при разработках "сверху вниз", подготавливая элементы, которые еще предстоит реализовать.
Программисты всегда заботятся об эффективности, в частности, о скорости выполнения. По этой причине они могут избегать создания метода, зная, что всякий вызов метода требует дополнительных расходов времени. Хорошие программисты также заботятся об эффективности, но они заботятся и о качестве ПО. Есть три причины, по которым крайне редко следует ограничивать себя в создании методов.
- Архитектура современных компьютеров позволяет резко снизить накладные расходы на вызов метода.
- За исключением случаев, когда вызов появляется во внутреннем цикле и выполняется многократно, доля расходов на вызов пренебрежимо мала в сравнении с общим временем работы, по крайней мере, для программ, выполняющих интенсивные вычисления (если общее время работы мало, то нет и особого смысла говорить об эффективности). Обычно имеет смысл заботиться о критических участках программы, на долю которых приходятся основные затраты времени.
- Не стоит самому беспокоиться даже о критически важных методах, для которых потери на вызов могут быть ощутимы. Можно положиться на компилятор EiffelStudio, который способен в режиме "оптимизации" выполнять автоматическое встраивание метода в точки вызова. Студия позволяет управлять этим процессом, задавая, например, максимальный размер метода, для которого допускается преобразование его во встраиваемый (in line) метод.
Изучение сложности алгоритмов даст нам лучшие рамки для обсуждения эффективности, выражая производительность как функцию от размера множества данных.