Читаем Фундаментальные алгоритмы и структуры данных в Delphi полностью

В Delphi1 и Delphi 2 приходится применять другие способы. Существует два метода. Первый - написать метод Assert, реализация которого должна быть пустой при создании окончательной версии приложения и будет содержать проверку с вызовом Raise в противном случае. Пример такой процедуры утверждения приведен в листинге 1.7.

Листинг 1.7. Процедура утверждения для Delphi1 и Delphi 2


procedure Assert(aCondition : boolean; const aFailMsg : string);

begin

{$IFDEF UseAssert}

if not aCondition then

raise Exception.Create(aFailMsg);

{$ENDIF}

end;


Как видно из листинга, применяется директива $IFDEF компилятора. Несмотря на то что приведенная процедура проста в использовании и легко может быть вызвана из основного кода, она подразумевает, что в окончательной версии приложения будет присутствовать вызов пустой процедуры. Альтернативным вариантом организации проверки утверждений может быть использование оператора $IFDEF не в процедуре, а в основном коде при вызове процедуры. В таком случае блоки проверки будут выглядеть следующим образом:


...

{$IFDEF UseAssert}

Assert (MyPointer <> nil, "MyPointer should be allocated by now");

{$ENDIF}

MyPointer^.Field := 0;

...


Преимущество последнего метода заключается в том, что процедура в окончательном варианте выполняемого файла отсутствует совсем. Поскольку в настоящей книге все коды предназначены для компиляции на всех версиях Delphi, используется процедура Assert, код которой показан в листинге 1.7.

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

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

И последний тип утверждений - инвариант (invariant). Он представляет собой нечто среднее между предусловием и постусловием. Это утверждение, которое находится в середине кода и гарантирует, что определенная часть функции выполняется корректно.

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

Классическим примером может служить исключение "List index is out of bounds" (Индекс в списке вышел за допустимые пределы), особенно тот случай, когда используется индекс -1. Ошибка подобного типа вызвана тем, что программист не проверяет индекс элемента перед тем, как записать или считать его из TList. Код объекта TList проверяет все передаваемые ему индексы элементов. Если индекс находится вне допустимого диапазона, возникает исключение. Пользователь приложения не может вызвать такую ошибку (по крайней мере, это покажется глубоко бессмысленным для большинства пользователей). Ошибка возникает исключительно из-за недостаточного объема проведенного тестирования. По мнению автора, это исключение должно быть утверждением.

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

Перейти на страницу:

Похожие книги

C++
C++

С++ – это универсальный язык программирования, задуманный так, чтобы сделать программирование более приятным для серьезного программиста. За исключением второстепенных деталей С++ является надмножеством языка программирования C. Помимо возможностей, которые дает C, С++ предоставляет гибкие и эффективные средства определения новых типов. Используя определения новых типов, точно отвечающих концепциям приложения, программист может разделять разрабатываемую программу на легко поддающиеся контролю части. Такой метод построения программ часто называют абстракцией данных. Информация о типах содержится в некоторых объектах типов, определенных пользователем. Такие объекты просты и надежны в использовании в тех ситуациях, когда их тип нельзя установить на стадии компиляции. Программирование с применением таких объектов часто называют объектно-ориентированным. При правильном использовании этот метод дает более короткие, проще понимаемые и легче контролируемые программы. Ключевым понятием С++ является класс. Класс – это тип, определяемый пользователем. Классы обеспечивают сокрытие данных, гарантированную инициализацию данных, неявное преобразование типов для типов, определенных пользователем, динамическое задание типа, контролируемое пользователем управление памятью и механизмы перегрузки операций. С++ предоставляет гораздо лучшие, чем в C, средства выражения модульности программы и проверки типов. В языке есть также усовершенствования, не связанные непосредственно с классами, включающие в себя символические константы, inline-подстановку функций, параметры функции по умолчанию, перегруженные имена функций, операции управления свободной памятью и ссылочный тип. В С++ сохранены возможности языка C по работе с основными объектами аппаратного обеспечения (биты, байты, слова, адреса и т.п.). Это позволяет весьма эффективно реализовывать типы, определяемые пользователем. С++ и его стандартные библиотеки спроектированы так, чтобы обеспечивать переносимость. Имеющаяся на текущий момент реализация языка будет идти в большинстве систем, поддерживающих C. Из С++ программ можно использовать C библиотеки, и с С++ можно использовать большую часть инструментальных средств, поддерживающих программирование на C. Эта книга предназначена главным образом для того, чтобы помочь серьезным программистам изучить язык и применять его в нетривиальных проектах. В ней дано полное описание С++, много примеров и еще больше фрагментов программ.

Мюррей Хилл , Бьёрн Страуструп , Бьярн Страустрап

Программирование, программы, базы данных / Программирование / Книги по IT