Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Прочая околокомпьтерная литература » Основы объектно-ориентированного программирования - Бертран Мейер

Основы объектно-ориентированного программирования - Бертран Мейер

Читать онлайн Основы объектно-ориентированного программирования - Бертран Мейер

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 113 114 115 116 117 118 119 120 121 ... 188
Перейти на страницу:

[x]. Повторно используемый модуль должен быть специфицирован.

[x]. Язык программирования должен поддерживать механизм утверждений.

[x]. Спецификации являются частью самого ПО.

Лекция 12. Когда контракт нарушается: обработка исключений

Нравится это или нет, но не стоит притворяться, несмотря на все статические предосторожности, некоторые неожиданные и нежелательные события рано или поздно возникнут при одном из выполнений системы. Такие ситуации известны как исключения, и нужно должным образом уметь справляться с ними.

Базисные концепции обработки исключений

Литература по обработке исключений зачастую не очень точно определяет, что вызывает исключение. Как следствие, механизм исключений, представленный в таких языках программирования как PL/I и Ada, часто неправильно используется: вместо того, чтобы резервироваться только для истинно чрезвычайных ситуаций, они заканчивают службу как внутрипрограммные инструкции goto, нарушающие принцип Защищенности.

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

Отказы

Неформально исключение это аномальное событие, прерывающее выполнение программы. Для получения содержательного определения полезно вначале рассмотреть понятие отказа, непосредственно следующее из идеи контракта.

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

Так должно быть, но в жизни не все происходит так, как должно быть. И мы должны ожидать, что рано или поздно при очередном вызове программы она не сможет выполнить свой контракт. Произойдет системное прерывание, или будет вызвана программа в состоянии, не удовлетворяющем ее предусловию, или в заключительном состоянии будет нарушено постусловие либо инвариант (в двух последних случаях предполагается мониторинг утверждений в период выполнения).

Такие ситуации будем называть отказом (failure).

Определения: успех, отказ

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

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

Исключения

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

Определение: исключение

Исключение - событие периода выполнения, которое может стать причиной отказа программы.

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

Изучение программных аномалий в предыдущей лекции привело к появлению терминов неисправность (fault) - для событий, приводящих к пагубным последствиям при выполнении программы, дефект (defect) - неадекватность программной системы, способная привести к отказам, ошибка (error) - неверные решения разработчика или проектировщика, приводящие к дефектам. Отказ - это неисправность; исключение, зачастую, тоже неисправность, но таковым не является, если его возможное появление предвиделось, и программа может справиться с возникшей ситуацией.

Источники исключений

Исключения можно классифицировать, разделив их на категории.

Определение: исключительные ситуации

Исключения могут возникать при выполнении программы r в результате следующих ситуаций.

1 Попытка квалифицированного вызова a.f и обнаружение, что a = Void.

2 Попытка присоединить значение Void к развернутой (expanded) цели.

3 Выполнение невозможной или запрещенной операции, обнаруживаемое аппаратно или операционной системой.

4 Вызов программы, приводящей к отказу.

5 Предусловие r не выполняется на входе.

6 Постусловие r не выполняется на выходе.

7 Инвариант класса не выполняется на входе или выходе.

8 Инвариант цикла не выполняется в результате инициализации в предложении from или после очередной итерации тела цикла.

9 Итерация тела цикла не уменьшает вариант цикла.

10 Не выполняется утверждение инструкции check.

11 Выполнение инструкции, явно включающей исключение.

Случай (1) отражает одно из основных требований к использованию ссылок: вызов a.f имеет смысл, когда к a присоединен объект, другими словами, когда a не void. Это обсуждалось в лекции 8 при рассмотрении динамической модели.

Случай (2) также имеет дело с void значениями. Напомним, что "присоединение" (attachment) покрывает присваивание и передачу аргументов, имеющих одинаковую семантику. В разделе "Гибридное присоединение" лекции 8 отмечалась возможность присваивания ссылки развернутой цели, в результате чего происходит копирование объекта. Но это предполагает существование объекта, но если источник void, то присоединение вызовет исключение.

Случай (3) следствие сигналов, посылаемых приложению операционной системой.

Случай (4) возникает при отказе программы, как результат возникновения в ней исключения, с которым она не смогла справиться. Более подробно это будет рассмотрено ниже, но пока обратите внимание на правило, вытекающее из (4):

Отказы и исключения

Отказ программы - причина появления исключения в вызывающей программе.

Случаи (5)-(10) могут встретиться только при мониторинге утверждений, включенных на соответствующем уровне: assertion (require) для (5), assertion (loop) для (8) и (9) и так далее.

Случай (11) предполагает вызов процедуры raise, выбрасывающей (зажигающей) исключения. Такая процедура будет рассмотрена чуть позднее.

Ситуации отказа

Рассматривая список возможных исключений, полезно определить, когда может встретиться отказ (причина исключения у вызывающей программы):

Определение: случаи отказа

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

Определения отказа и исключения взаимно рекурсивны: отказ возникает из-за появления исключений, а одна из причин исключения - отказ при вызове программы (случай (4)).

Обработка исключений

Теперь у нас есть определение того, что может случиться, - исключения - и того, с чем мы бы не хотели столкнуться в результате появления исключения, - отказа. Давайте разыскивать способы справляться с исключениями так, чтобы не возникли отказы. Что может сделать программа, когда ее выполнение прервано из-за нежелательного поведения?

Помощь в нахождении разумного ответа могут дать примеры того, как не следует поступать в подобных ситуациях. Ими мы обязаны механизму сигналов языка C, пришедшему из Unix, и одному учебнику по языку Ada.

Как не следует делать это - C-Unix пример

Первым контрпримером механизма (наиболее полно представленным в Unix, но доступным и на других платформах, реализующих C) является процедура signal, вызываемая в следующей форме:

signal (signal_code, your_routine)

с эффектом вызова обработчика исключения - программы your_routine, когда выполнение текущей программы прерывается, выдавая соответствующий код сигнала (signal_code). Код сигнала - целочисленная константа, например, SIGILL (неверная инструкция - illegal instruction) или SIGFPE (переполнение с плавающей точкой - floating-point exception). В программу можно включить сколь угодно много вызовов процедуры signal, что позволяет обрабатывать различные, возможные ошибки.

1 ... 113 114 115 116 117 118 119 120 121 ... 188
Перейти на страницу:
На этой странице вы можете бесплатно скачать Основы объектно-ориентированного программирования - Бертран Мейер торрент бесплатно.
Комментарии