Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Лекции.doc
Скачиваний:
44
Добавлен:
23.03.2015
Размер:
741.89 Кб
Скачать

Создание процедурных абстракций

В данном разделе мы рассмотрим ряд проблем, возникающих при создании процедурных абстракций. Процедуры, как и дру­гие виды абстракций, которые мы рассмотрим позднее, в процессе своего создания необходимо минимизировать. В них должны быть реализованы только необходимые функции. Это предоставляет разработчику большую свободу, позволяя ему создать более эф­фективную версию. Например, если приведенная на рис. 3.5 процедураsortпозволяет модифицировать аргумент, заданный массивом, то это уменьшает занимаемый ею объем памяти. Од­нако список значимых для пользователя подробностей такого рода должен быть ограничен.

К одному из таких пунктов, который обычно остается неопре­деленным, относится сам метод, используемый в конкретной ре­ализации. Обычно пользователям предоставляется свобода в его выборе. (Впрочем, имеются исключения; например, процедура, работающая с числами, может быть ограничена хорошо извест­ным числовым методом с тем, чтобы при округлении ее работа при­водила к известным, четко определяемым погрешностям.) Также могут быть оставлены неопределенными некоторые выполняемые процедурой функции. В такой ситуации процедура становится недоопределенной.Это означает, что для определенных значений входных параметров на выходе вместо единственного правиль­ного результата имеется набор допустимых результатов. Реали­зация может ограничивать этот набор только одним значением, однако он может быть любым из числа допустимых.

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

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

Недоопределенная абстракция может иметь детерминирован­ную реализацию, т. е. такую, которая, будучи вызванной два раза с идентичными входными данными, выполняется одинаково. Обе реализации процедурыsearch, приведенные на рис. 3.4,являются детерминированными. (Недетерминированные реализации тре­буют использования своих собственных переменных, описанных в приложении А. В настоящей работе они не рассматриваются.)

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

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

Наконец, процедурадолжнадействительно выполнять неко­торыефункции.Процедуры создаются в процессе написания про­граммы и служат цели упрощения и облегчения работы с ней, а также создания более ясной структуры программы. При этом программа становится более легко понимаемой. Однако сущест­вует опасность введения слишком большого числа процедур. Например, приведенная на рис. 3.6процедураmergeполезна потому, что ее назначение четко выражено, а также потому, что она позволяет нам отделить друг от друга задачи сортировки и слияния. Это делает процедуруmerge_sortболее ясной и понятной. По всей видимости, дальнейшая декомпозиция является избыточ­ной. Например, тело цикла в процедуреmergeможет быть вы­делено в процедуру, однако в этом случае ее назначение трудно определить.

Некоторые описанные ранее процедуры являются частичными, другие -общими. Подобная дихотомия поднимает вопрос о том, в каких случаях выгоднее определять частичную абстракцию. Частичные процедуры не так безопасны, как общие, поскольку они требуют от пользователя выполнения требований, заданных в предложенииrequires. Если эти требования не удовлетворены, то поведение процедуры становится неопределенным, что может привести к неверной работе программы. Например, при задании для процедурыsearchнеупорядоченного массива она может воз­вратить неверный индекс. Эта ошибка может оставаться необна­руженной долгое время после возврата из процедурыsearch. Вследствие этого причина ошибки будет неясна, а объекты дан­ных могут быть разрушены.

С другой стороны, частичные процедуры могут оказаться бо­лее эффективными в реализации, чем общие. Например, если про­цедура searchдолжна работать даже в том случае, если массив не был упорядочен, то ни одна из реализаций, приведенных на рис. 3.4,не будет правильной. В этом случае можно будет исполь­зовать только менее эффективный вариант, при котором анали­зируются все элементы массива.

При выборе между частичной и общей процедурами мы должны придерживаться определенных соглашений. С одной стороны, кри­терием должна являться эффективность. С другой —корректное выполнение с меньшим числом потенциальных ошибок. Каким образом осуществить такой выбор? Одним из важных факторов является ожидаемая область применения. Если процедура соз­дается для общего пользования (например, доступна как часть библиотеки программ), то соображения безопасности играют су­щественную роль. В такой ситуации невозможно осуществить статистический анализ всех обращений к процедуре, позволяющий удостовериться в том, что необходимые требования удовлет­ворены. Следовательно, в этом случае полагаться на такой ана­лиз неразумно.

Другой случай предполагает использование некоторых про­цедур в ограниченном контексте. Такой была ситуация, когда процедурыmergeиmerge_sortвызывались только программойsort, использующей метод сортировки слиянием. В ограничен­ном контексте легко обеспечить выполнение необходимых требо­ваний. Например, два массива,, передаваемые процедуреmerge, только что были отсортированы. Следовательно, мы имеем без­опасное поведение, не жертвуя при этом эффективностью.

Наконец, необходимо наличие четкой и понятной специфика­ции. Написание хороших спецификаций является предметом следующих лекций.

Соседние файлы в папке AlgStr