- •1. Введение
- •1.1. Декомпозиция и абстракция
- •1.2. Абстракция
- •1.2.1. Абстракция через параметризацию
- •1.2.2. Абстракция через спецификацию
- •1.2.3. Виды абстракций
- •3. Процедурная абстракция
- •3.2. Спецификации
- •3.3. Спецификации процедурных абстракций
- •3.4. Реализация процедур
- •3.5. Более обобщенные процедуры
- •3.6. Создание процедурных абстракций
- •3.7. Заключение
- •4. Абстракции данных
- •4.1. Спецификации для абстракций данных
- •4.2.1. Реализация на языке clu
- •4.2.2. Замечания по поводу операций up и down
- •4.3. Использование абстракций данных
- •4.4. Реализация полиномов
- •4.5. Пояснения для понимания реализаций
- •4.5.1. Функция абстракции
- •4.5.2. Инвариант представления
- •4.6.3. Сохранение инварианта представления
- •4.5.4. Изменяемые представления
- •4.6. Параметризованные абстракции данных
- •4.7. Списки
- •4.8. Упорядоченные списки
1.2.3. Виды абстракций
Абстракции через параметризацию и через спецификацию являются мощными средствами создания программ. Они позволяют нам определить три различных вида абстракций: процедурную абстракцию, абстракцию данных и абстракцию через итерацию. В общем случае каждая процедурная абстракция, абстракция через данные и абстракция через итерацию используют оба способа.
Например, абстракцию sqrt можно сравнить о операцией: она абстрагирует отдельное событие или задачу. Мы будем ссылаться к абстракциям такого рода как к процедурным абстракциям. Отметим, что абстракция sqrt включает в себя как абстракцию через параметризацию, так и абстракцию через спецификацию.
Процедурная абстракция является мощным средством. Она позволяет нам расширить заданную некоторым языком программирования виртуальную машину новой операцией. Такой вид расширения наиболее полезен в том случае, когда мы работаем с задачами, которые легко представить в виде набора независимых функциональных единиц. Однако часто оказывается более удобным добавить к виртуальной машине несколько объектов данных с новыми типами.
Поведение объектов данных наиболее естественно представлять в терминах набора операций, применимых к данным объектам. Такой набор включает в себя операции по созданию объектов, получению информации от них и, возможно, их модификации. Например, операции push и pop принадлежат к классу операций, имеющих смысл при работе со стеками, в то время как для работы с целыми числами используются обычные арифметические операции. Таким образом, абстракция данных (или тип. данных) состоит из набора объектов и набора операций, характеризующих поведение этих объектов.
В качестве примера рассмотрим мультинаборы (multisets). Мультинаборы сходны с обычными наборами, за исключением того, что элемент может входить в мультинабор несколько раз. Операции для работы с подобными мультинаборами включают в себя операции empty, insert, delete, number_of и size. Эти операции создают пустой мультинабор, удаляют и добавляют в него элементы, вычисляют, сколько раз данный элемент входит в мультинабор и сколько всего элементов содержится в мультинаборе. Данные операции могут быть реализованы в языке программирования через соответствующие процедуры. Программисты, работающие с мультинаборами, не должны беспокоиться о том, каким образом эти процедуры реализованы. Для них операции empty, insert, delete, number_of и size являются абстракциями, определяемыми операторами типа
The size of the multi.set insert (s, e) is equal to size (s) + I (Размер мультинабора insert (s, e) равен размеру size (s) + 1)
For all e, the number, of timese occurs in the multi_ set empty ( )is0. (Для всех e число вхождений e в пустой мультинабор empty ( ) равно 0.)
Важно отметить, что каждый из этих операторов работает сразу с несколькими операциями. Мы не приводим независимые определения каждой операции, но скорее определяем их через взаимосвязи. Этот акцент на взаимосвязях между операциями и делает абстракцию данных существенно отличной от набора процедур. Важность этого отличия обсуждается на протяжении всей книги.
В дополнение к процедурным абстракциям и абстракциям данных мы рассмотрим также абстракцию через итерацию. Абстракция через итерацию дает возможность не рассматривать информацию, не имеющую прямого отношения к управляющему потоку или циклу. Типичная абстракция итерации позволяет нам обрабатывать все элементы мультинабора без накладывания каких-либо ограничений на последовательность обработки.
Далее мы покажем, как осуществлять декомпозицию программы на базе абстракции через итерацию. Акцент будет делаться на абстракции данных. Мы считаем, что, хотя процедурные абстракции и абстракции через итерацию и играют существенную роль, организация процесса программирования начинается, как правило, с абстракции данных.
Последующие несколько глав посвящены трем перечисленным видам абстракций — что они из себя представляют, как описывается их поведение и как происходит их реализация. Мы начнем с описания языка программирования CLU, специально созданного для работы по методике, описанной в данной книге, поддерживающего каждый из описываемых видов абстракций. Абстракции на языке CLU реализуются сравнительно просто, поэтому в главах с 3 по 6 используется именно этот язык. В седьмой главе мы обсудим, как реализовать абстракции на языке Паскаль.
В последней части книги рассматривается использование абстракций при составлении программ. Обсуждаются этапы составления программ, их проектирование и реализация. Книга включает в себя ряд практических советов, помогающих реилль проблемы, возникающие при составлении реальных программ.
Дополнительная литература
Boehnn, Barry W,, 1976. Software engineering. IEEE Transactions on Computers C-25 (12): 1226—1241.
Brooks, Frederick P., Jr., 1975. The Mythical Man-Month, Reading, Mass,.: Addison-Wesley Publishing Co.
Buxton, John M., Peter Naur, and Brian Randell (eds.), 1976. Software engineering concepts and techniques. In Proceedings of the NATO Conference (New York: Petrocelli/Charter).
Gries, David (ed.), 1978. Part 1: viewpoints on programming. In Programming Methodology, A Collection of Articles by Members of IF IP W02.3 (New York: Springer-Verlag), pp. 7—74.
Упражнения
I.I. Опишите знакомую вам иерархию абстракции. 1.2. Выберите написанную или используемую вами процедуру и рассмотрите, каким образом в ней реализована абстракция через спецификацию и через параметры.
Еще более важным является эффект, оказываемый данным стилем программирования. В объектно-ориентированном языке внимание фокусируется на объектах, их смысловом значении и их поведении. Эта особенность хорошо сочетается с методологией программирования, описываемой в данной книге. В этой методологии абстракции данных, состоящие из объектов данных и операций для работы с ними, являются наиболее важным средством организации программ.
Упражнения
2.1. Вычисление наибольшего общего делителя способом последовятельного вычитания (рис. 2.1) является недостаточно эффективным. Переделайте функцию gcd с использованием деления. 2.2. Создайте процедуру с заголовком
тах = proc (a: array [int]) returns (int)
Процедура max должна возвращать максимальное значение в а. Вы можете считать, что массив а является непустым.
2.3. Проиллюстрируйте вызов процедуры gcd на рис. 2.1 диаграммой по аналогии с рис. 2.5.
2.4. Массив, передаваемый в качестве аргумента процедуре remove, dupis на рис. 2.5, содержит дублирующие элементы 1 и 3. Почему эти элементы не показаны на рис. 2,5, в?
2.5. Разработайте процедуру, которая определяет, является ли заданная символьная строка палиндромом. (Палиндром читается одинаково слева и справа, например «deed».) 2.6. Напишите процедуру с заголовком
combine =z proc (a: array [int 1, comb: proctype (int, int) returns (int)) returns (int)
Она должна объединять все элементы массива а, используя аргумент процедуры comb. Например, combine (a, int$add) складывает все элементы массива а. Вы можете считать, что массив а содержит по крайней мере 2 элемента.
2.7. Напишите процедуру, просматривающую поток и возвращающую из него последующее слово, где слово представляет собой любую комбинацию символов, исключая пробелы и разделители строк. Вы можете считать, что поток позиционцрован по первому символу слова.
2.8. Реализуйте процедуру, пропускающую пробелы в потоке. Она должна возвращать поток, позиционированный по первому символу, отличному от пробела, или символу конца файла, если символы, отличные от пробела, отсутствуют,
