Тверской государственный университет
Опубликован: 03.10.2011 | Доступ: свободный | Студентов: 3242 / 54 | Оценка: 4.33 / 3.83 | Длительность: 19:48:00
ISBN: 978-5-9963-0573-5
Лекция 9:

Подпрограммы, функциональная абстракция, скрытие информации

< Лекция 8 || Лекция 9: 1234 || Лекция 10 >
Аннотация: Управляющие структуры предыдущей лекции — цикл, составной и условный операторы, их варианты — дают нам базисные механизмы планирования порядка выполнения операторов. Если бы они были единственными средствами, то нам пришлось бы задавать поток управления со всеми деталями. Для сложных программ глубина вложенности стала бы главным препятствием на пути понимания программы.
Ключевые слова: дифференциальное уравнение, метод решения, псевдокод, детализация, абстракция, подпрограмма, routine, subprogram, subroutine, method, eiffel, feature, attribute, алгоритмическая, алгоритм, подмножество, preview, traversal, end-station, класс, условные операторы, re-route, ПО, метод класса, список, формальный аргумент, фактический аргумент, определение, сигнатура метода, аргумент, запрос, сообщение об ошибке, значение, предусловие, тело метода, последовательность операторов, постусловие, сигнатура, реализация интерфейса, traffic, знание, количество информации, доступ, интерфейс, наследование, динамическое связывание, compilable, output, инициализация объекта, вызов функции, тип значений, объявление функции, тело функции, ключевое слово, объект, вызов метода, дополнительные расходы, производительность, множества, останов, ECF, файл, terminate, доказательство, аргумент функции, входные данные, постановка задачи, произвольное, Windows, technique, software, specification, with, communications, ACM, AND, criteria, used, incremental

Чтобы держать сложность под контролем, привлечем еще один проверенный временем прием решения задач: выделение подзадач. Подзадача — это задача, чье решение может помочь в решении других задач. Если мы умеем решать подзадачу и умеем представить это решение в виде элемента управления, простого или сложного, то можно дать имя этой подзадаче и использовать новый элемент под этим именем. Этот прием известен как функциональная абстракция, а соответствующий программный механизм — как подпрограмма (routine).

8.1. Выводимость "снизу вверх" и "сверху вниз"

Почему полезно выделять подзадачи? Можно привести два дополняющих ответа.

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

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

В программировании соответствующая конструкция, задающая решение подзадачи, известна как подпрограмма.

Почувствуй терминологию

Подпрограммы под любым другим именем

У английского термина "routine" есть синонимы - "subprogram" и "subroutine".

Подпрограмма может возвращать результат, и тогда ее называют функцией. Подпрограмма, не возвращающая результат, называется процедурой. Оба эти термина часто используются для ссылок на подпрограммы любого типа. В языке С, например, применяется единственный термин - "функция". В добавлении к этой терминологической путанице в ОО-языках добавляют новый термин - "метод" (method), означающий то же, что и подпрограмма, но добавляющий дополнительную сложность из-за совпадения с общим употреблением этого слова. Вот пара примеров: "Нет никакого метода в написанных им методах" или "От его методов можно сойти с ума1В Eiffel для составляющих класса используется единый термин "feature", который мы, за неимением лучшего, переводим как "компонент". Калька слова feature (фича) (используемая в профессиональном жаргоне) кажется неприемлемой. Компонент - feature - может быть подпрограммой (routine) или переменной, и тогда в Eiffel он называется атрибутом (attribute). Несмотря на справедливую критику термина "метод", именно он, а не термин "подпрограмма", используется при переводе, когда речь идет о методах (routine) класса.".

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

8.2. Подпрограммы как методы (routines as features)

Подпрограмма характеризует алгоритм (операцию), применимый ко всем экземплярам класса. Как таковая, она является одним из двух видов характерных компонентов класса, задавая метод класса. Другой характеристикой класса, изучаемой в следующей лекции, является атрибут.

Будучи методом, подпрограмма имеет:

  • объявление, которое появляется в тексте класса в разделе feature и описывает все свойства подпрограммы. Объявление подпрограммы также называется ее реализацией;
  • интерфейс, который выделяет только подмножество свойств подпрограммы, а именно те, которые интересны клиентам подпрограммы. Интерфейс метода отображается в контрактном облике класса.

Мы уже сталкивались со многими подпрограммами, зная их как методы: класса. Например:

  • наш самый первый метод, explore в классе PREVIEW, является подпрограммой. Это же верно и для метода из предыдущей лекции traverse, который в разных вариантах предлагался для реализации;
  • при изучении того, как использовать класс, зная его интерфейс, мы рассматривали класс STATION, который в разделе feature объявлял методы — команду remove_all_segments и запрос i_th (в этом же разделе у этого класса были заданы атрибуты, такие как southend и count).

В случае самостоятельного задания метода необходимо дать полное объявление подпрограммы, для использования метода достаточно знания его интерфейса, например:

remove_all_segments
    — Удалить все станции за исключением конечной, юго-западной.
  ensure
    only_one_left: count = 1
    both_ends_same: south_end = north_end

Полный текст подпрограммы можно видеть, изучая класс STATION. Теперь мы приступаем к изучению того, как самостоятельно писать объявления методов.

8.3. Инкапсуляция (скрытие) функциональной абстракции

Последний пример изучения условного оператора дает хороший пример определения "функциональной абстракции" в форме подпрограммы. Внешний цикл, появляющийся в методе traverse из класса ROUTES, записан как

from ... invariant ... variant ... until ... loop
  if Line8.item .is_exchange then
    show_blinking_spot (Line8.item.location)
  elseif Line8.item.is_railway_connection then
    show_big_red_spot (Line8.item.location)
  else
    show_spot (Line8.item.location)
  end
    Line8.forth
end
Листинг 8.1.

В этой записи нас беспокоит не только повторение кода, но и отсутствие распознавания того факта, что действия применяются к одному и тому же объекту — Line8.item. Это свойство становится более ясным, если мы выделим условную структуру в самостоятельный метод. Цикл тогда будет выглядеть так:

from ... invariant ... variant ... until ... loop
  show_station( Line8.item)
  Line8.forth
end
Листинг 8.2.

Он использует новый метод show_station, чье объявление появляется в том же классе ROUTES:

show_station (s: STATION)
    -Подсветить s в форме, соответствующей ее статусу
  require
    station_exists: s /= Void
  do
    if s.is_exchange then
      show_blinking_spot (s.location)
    elseif s.is_railway_connection then
      show_big_blue_spot (s.location)
    else
      show_spot (s.location)
    end
end
< Лекция 8 || Лекция 9: 1234 || Лекция 10 >
Ирина Калашникова
Ирина Калашникова

Добрый день, подскажите на тест после каждой лекции сколько дается попыток? 

Наталья Король
Наталья Король

Что это значит?) Зранее спасибо)