Бертран Мейер - Основы объектно-ориентированного программирования
- Название:Основы объектно-ориентированного программирования
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Бертран Мейер - Основы объектно-ориентированного программирования краткое содержание
Фундаментальный учебник по основам объектно-ориентированного программирования и инженерии программ. В книге подробно излагаются основные понятия объектной технологии – классы, объекты, управление памятью, типизация, наследование, универсализация. Большое внимание уделяется проектированию по контракту и обработке исключений, как механизмам, обеспечивающим корректность и устойчивость программных систем.
В книге Бертрана Мейера рассматриваются основы объектно-ориентированного программирования. Изложение начинается с рассмотрения критериев качества программных систем и обоснования того, как объектная технология разработки может обеспечить требуемое качество. Основные понятия объектной технологии и соответствующая нотация появляются как результат тщательного анализа и обсуждений. Подробно рассматривается понятие класса - центральное понятие объектной технологии. Рассматривается абстрактный тип данных, лежащий в основе класса, совмещение классом роли типа данных и модуля и другие аспекты построения класса. Столь же подробно рассматриваются объекты и проблемы управления памятью. Большая часть книги уделена отношениям между классами – наследованию, универсализации и их роли в построении программных систем. Важную часть книги составляет введение понятия контракта, описание технологии проектирования по контракту, как механизма, обеспечивающего корректность создаваемых программ. Не обойдены вниманием и другие важные темы объектного программирования – скрытие информации, статическая типизация, динамическое связывание и обработка исключений. Глубина охвата рассматриваемых тем делает книгу Бертрана Мейера незаменимой для понимания основ объектного программирования.
Основы объектно-ориентированного программирования - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Вот другой пример - наш старый друг стек. Нашей библиотеке потребуется общий класс STACK [G] , который будет отложенным, так как он должен покрывать всевозможные реализации. Его собственные потомки, такие как FIXED_STACK и LINKED_STACK , будут описывать конкретные реализации. Одной из отложенных процедур класса STACK является put :
put (x: G) is
-- Поместить x на вершину.
require
not full
deferred
ensure
not_empty: not empty
pushed_is_top: item = x
one_more: count = old count + 1
end
Булевские функции empty и full (также отложенные на уровне STACK ) выражают свойство стека быть пустым и заполненным.
Только с помощью утверждений отложенные классы достигают своей полной силы. Как уже отмечалось (хотя детали появятся через две лекции), предусловия и постусловия применимы ко всем переопределениям процедуры. Это особенно важно в отложенном случае: в нем такие утверждения будут ограничивать все допустимые реализации. Таким образом, приведенная спецификация ограничивает все варианты put в потомках класса STACK .
Благодаря использованию утверждений, можно сделать отложенные классы достаточно информативными и семантически богатыми, несмотря на отсутствие у них реализаций.
В конце этой лекции мы вновь обратимся к отложенным классам и исследуем глубже их роль в процессе ОО-анализа, проектирования и реализации.
Способы изменения объявлений
Возможность изменить объявление компонента - переопределить или дать его реализацию - обеспечивает гибкость и последовательное проведение разработки. Имеется еще два метода, усиливающих эти качества:
[x].Возможность изменить объявление функции на атрибут.
[x].Простой способ сослаться на первоначальную версию в теле нового определения.
Повторное объявление функции как атрибута
Повторные объявления позволяют активно применять один из центральных принципов модульности - принцип Унифицированного Доступа (Uniform Access).
Напомним (см. лекцию 3), что этот принцип утверждает (первоначально в менее технических терминах, но сейчас мы можем позволить себе быть более точными), что с точки зрения клиента не должно быть никакой существенной разницы между атрибутом и функцией без аргументов. В обоих случаях компонент является запросом и все, что их отличает, - это их внутреннее представление.
Первым примером этого был класс, описывающий банковские счета, в котором компонент balance мог быть реализован как функция, которая добавляет вклады и вычитает снимаемые суммы, или как атрибут, изменяемый по мере необходимости так, чтобы отражать текущий баланс. Для клиента это было все равно (за исключением, возможно, эффективности).
С появлением наследования можно пойти дальше и позволить, чтобы в классе наследуемая функция была переопределена как атрибут.
Наш прежний пример хорошо подходит для иллюстрации. Пусть имеется класс ACCOUNT1 :
class ACCOUNT1 feature
balance: INTEGER is
-- Текущий баланс
do
Result := list_of_deposits.total - list_of_withdrawals.total
end
...
End
Тогда в потомке может быть выбрана вторая реализация из нашего первоначального примера, переопределяющая balance как атрибут:
class ACCOUNT2 inherit
ACCOUNT1
redefine balance end
feature
balance: INTEGER
-- Текущий баланс
...
end
По-видимому, в классе ACCOUNT2 нужно будет переопределить некоторые процедуры, такие как withdraw и deposit , чтобы, кроме других своих обязанностей они еще модифицировали нужным образом balance , сохраняя в качестве инварианта свойство: balance = list_of_deposits.total - list_of_withdrawals.total .
В этом примере новое объявление является переопределением. Его результатом может также оказаться превращение отложенного компонента в атрибут. Например, пусть в отложенном классе LIST имеется компонент
count: INTEGER is
-- Число вставленных элементов
deferred
end
Тогда в реализации списка этот компонент может быть реализован как атрибут:
count: INTEGER
Если нас попросят применить эту классификацию, чтобы разбить компоненты на атрибуты и подпрограммы, то мы условимся рассматривать отложенный компонент как подпрограмму, несмотря на то, что для отложенного компонента с результатом и без аргументов само понятие отложенности означает, что мы еще не сделали выбор, как его реализовать - функцией или атрибутом. Фраза "отложенный компонент" передает эту неопределенность и предпочтительней фразы "отложенная подпрограмма". |
Переобъявление функции как атрибута, объединенное с полиморфизмом и динамическим связыванием, приводят к полной реализации принципа Унифицированного Доступа. Сейчас можно не только реализовать запрос клиента вида a.service либо через память, либо посредством вычисления, но один и тот же запрос в процессе одного вычисления может в одних случаях запустить доступ к некоторому полю, а в других - вызвать некоторую функцию. Это может, в частности, случиться при выполнении одного и того же вызова a.balance , если по ходу вычисления a будет полиморфно присоединяться к объектам разных классов.
Обратного пути нет
Можно было бы ожидать, что допустимо и обратное переопределение атрибута в функцию без аргументов. Но нет. Присваивание - операция применимая к атрибутам, - становится бессмысленной для функций. Предположим, что a - это атрибут класса C , и некоторая подпрограмма содержит команду
a := some_expression
Если потомок C переопределит a как функцию, то эта функция будет не применима, поскольку нельзя использовать функцию в левой части присваивания.
Отсутствие симметрии (допустимо изменять объявление функции на объявление атрибута, но не наоборот) неприятно, но неизбежно и не является на практике серьезным препятствием. Оно означает, что объявление некоторого компонента атрибутом является окончательным и необратимым выбором, в то время как объявление его функцией все еще оставляет место для последующих реализаций через память, а не через вычисление.
Использование исходной версии при переопределении
Интервал:
Закладка: