Март 2011

Руководство по actionscript. часть 2, стр. 080

Вариант 2. Упростить код, но по-прежнему использовать один класс для исключительных ситуаций класса VirtualPet

В данном случае мы изменяем метод setName ( ) таким образом, чтобы проверка всех трех исключительных ситуаций выполнялась в одном операторе if. Этот вариант аналогичен предыдущему, но использует более сжатый код.

Вариант 3. Использовать отладочные сообщения для нахождения различий между ошибками.

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

Вариант 4. Создать пользовательский класс исключения для каждой исключительной ситуации.

Используя это вариант, мы создаем два пользовательских подкласса класса VirtualPetNameException: VirtualРеtlnsufficientDataException и VirtualPetExcessDataException. Этот вариант обеспечивает наибольшую степень детализации. Он позволяет программе независимо реагировать на три разновидности ошибок, относящихся к классу VirtualPet, используя формальную логику ветвлений.

Рассмотрим каждый из описанных вариантов.

Варианты 1 и 2. Использование одного пользовательского типа исключения. Первый вариант состоит в применении предыдущего описания метода setName ( ), которое генерирует ошибку одного и того же типа (VirtualPetNameException) для всех трех исключительных ситуаций, относящихся к классу Virtual Pet. Поскольку для генерации исключений этот метод использует класс VirtualPetNameException, а не класс Error, исключения класса Vi rtual Pet уже отличаются от других базовых исключений. Пользователи метода setName ( ) могут применять код, аналогичный следующему, для отличия ошибок, относящихся к классу VirtualPet, от других базовых ошибок:

try {

// Этот вызов метода setName( ) приведет к возникновению исключения // VirtualPetNameException. somePet. setName(«»);

// Другие инструкции в этом блоке try могут генерировать // другие базовые ошибки. Для демонстрационных целей

// мы непосредственно сгенерируем // базовую ошибку.

throw new Error(«A generic error.»); } catch (e:VirtualPetNameException) { // Здесь обрабатываются ошибки, связанные с именем объекта класса // VirtualPet.

Руководство по actionscript. часть 2, стр. 081

TraceC’An error occurred: » + e. message); traceCPlease specify a valid name.»); } catch (e:Error) { // Здесь обрабатываются все остальные ошибки. traceC’An error occurred: » + e. message);

}

Для большого количества приложений степень детализации, обеспечиваемая классом Virtual РеtNameExcept ion, оказывается достаточной. В этом случае мы должны по крайней мере переписать метод setName ( ), чтобы он не содержал избыточный код (трижды генерирующий исключение VirtualPetNameException). Рассмотрим переписанный код (представляющий вариант 2 из предыдущего списка):

public function setName (newName:String):void { if (newName. indexOfC «) == 0 11 newName == «»

jj newName. length > Virtual Pet. maxNameLength) { throw new VirtualPetNameException( );

}

petName = newName;

r*^! 1 Переписывание кода с целью улучшения его структуры без изменения существующего

-ttf

поведения называется рефакторингом.

Вариант 3. Применение конфигурируемых отладочных сообщений. Вариант 3 заключается в добавлении конфигурируемых отладочных сообщений в класс VirtualPetNameException. Варианты 1 и 2 позволяют отличить исключение класса VirtualPet от других исключений в приложении, но не позволяют отличить исключение «слишком длинное» от исключения «слишком короткое». Если вы чувствуете, что отладка проблемы, связанной с именем объекта класса Virtual Pet, затруднена отсутствием знания о том, является имя объекта класса VirtualPet слишком длинным или слишком коротким, можно изменить класс VirtualPetNameException таким образом, чтобы он принимал дополнительное описание (наподобие общеизвестного крестика на память). Рассмотрим измененный код класса VirtualPetNameException:

package zoo {

public class VirtualPetNameException extends Error { // Предоставляет конструктор, который позволяет указывать // пользовательское сообщение. Если пользовательское сообщение не // указано, используется стандартное сообщение об ошибке public function VirtualPetNameException (

message:String = «Invalid pet name specified.») {

super(message);

}

}

}

Чтобы воспользоваться модифицированным классом Virtual PetNameExcept ion в методе setName ( ), вернемся к коду метода setName ( ), использованному в варианте 1, и добавим отладочные сообщения об ошибке, как показано в следующем коде:

public function setName (newName:String):void { if (newName. indexOfC «) == 0) { // В данном случае отлично подойдет стандартное сообщение об ошибке, // поэтому не стоит утруждать себя указанием пользовательского сообщения // об ошибке.

Руководство по actionscript. часть 2, стр. 082

Throw new VirtualPetNameException( ): } else if (newName == «») {

// Вот пользовательское сообщение об ошибке «слишком короткое».

throw new VirtualPetNameException(«Pet name too short.»); } else if (newName. length > Virtual Pet. maxNameLength) {

// Вот пользовательское сообщение об ошибке «слишком длинное».

throw new Virtual PetNameException(«Pet name too long.»);

}

petName = newName;

}

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

try {

// Этот вызов метода setName( ) приведет к возникновению исключения

// VirtualPetNameException.

somePet. setName(«»); } catch (e:VirtualPetNameException) {

// Здесь обрабатываются ошибки, связанные с именем объекта класса

// VirtualPet. В данном случае полезным отладочным сообщением является:

// An error occurred: Pet name too short

// (Возникла ошибка: Имя животного слишком короткое).

Руководство по actionscript. часть 2, стр. 083

TraceC’An error occurred: » + е. message); } catch (e:Error) {

// Здесь обрабатываются все остальные ошибки.

traceC’An error occurred: » + е. message);

}

Вариант 4. Пользовательские подклассы класса VirtualPetNameException.

В варианте 3 мы добавляли конфигурируемые отладочные сообщения в класс Virtual PetNameExcept ion. Он помог выявить проблему в нашем коде на этапе разработки, однако этот вариант не позволяет программе выполнить независимые действия по восстановлению работоспособности после возникновения отдельных

ошибок класса VirtualPet. Чтобы программа могла выполнить отдельные ветки кода в зависимости от типа сгенерированной ошибки класса VirtualPet, нам потребуются пользовательские подклассы класса VirtualPetNameException, описанные в варианте 4.

I Если вы хотите, чтобы программа могла находить различия между исключительными м$ j * ситуациями, определяйте отдельный подкласс класса Error для каждой ошибки. Не по-

_ ц# лагайтесь исключительно на значение переменной message, чтобы реализовать логику

ветвлений. Если ваш пользовательский подкласс класса Error определяет конструктор, принимающий сообщение об ошибке в качестве параметра, используйте это сообщение только для отладки, но не для построения логики ветвлений.

Чтобы иметь возможность устанавливать различие между тремя исключительными ситуациями класса VirtualPet, создадим три подкласса класса Error: VirtualPetNameException, Virtual Pet Insufficient DataExcept ion и Vir tualPetExcessDataException. Первый класс непосредственно расширяет класс Error. Оба следующих класса расширяют класс VirtualPetNameException, поскольку мы хотим отличать эти специфические типы ошибок от базового исключения, обозначающего недопустимые данные.

Рассмотрим исходный код наших трех подклассов класса Error, представляющих ошибки класса VirtualPet:

// Код в файле VirtualPetNameException. as:

package zoo {

public class VirtualPetNameException extends Error { public function VirtualPetNameException (

message:String = «Invalid pet name specified.») {

super(message);

}

}

}

// Код в файле Virtual PetInsufficientDataException. as:

package zoo { public class VirtualPetlnsufficientDataException

extends VirtualPetNameException { public function VirtualPetlnsufficientDataException ( ) { super(«Pet name too short.»);

}

}

}

// Код в файле VirtualPetExcessDataException. as:

package zoo { public class VirtualPetExcessDataException

extends VirtualPetNameException { public function VirtualPetExcessDataException ( ) { super(«Pet name too long.»);

Каждый класс определяет значение своей переменной message и не позволяет изменять его в процессе использования. При обработке любого из описанных исключений класса VirtualPet наша программа будет руководствоваться типом данных исключения (а не значением переменной message) для нахождения различия между тремя типами исключений.

Руководство по actionscript. часть 2, стр. 084

Теперь, когда у нас появилось три типа исключений, добавим их генерацию в наш метод setName ( ):

public function setName (newName:String):void { if (newName. indexOfC «) == 0) {

throw new VirtualPetNameException( ); } else if (newName == «») {

throw new VirtualPetInsufficientDataException( ); } else if (newName. length > Virtual Pet. maxNameLength) {

throw new VirtualPetExcessDataException( );

}

petName = newName;

}

Обратите внимание, что в конструкторы различных исключений класса Virtual Pet не передаются никакие описания ошибок. Еще раз повторим, что описание каждого исключения задается в соответствующем пользовательском подклассе класса Error через его переменную message.

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

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

try {

b. setNameCнекоеИмяЖивотного»); } catch (e:VirtualPetExcessDataException) {

// Обработка ситуации «слишком длинное».

Руководство по actionscript. часть 2, стр. 085

TraceC’An error occurred: » + e. message);

traceCPlease specify a shorter name.»); } catch (e:VirtualPetlnsufficientDataException) {

// Обработка ситуации «слишком короткое».

traceC’An error occurred: » + e. message);

traceCPlease specify a longer name.»); } catch (e:VirtualPetNameException) {

// Обработка общих ошибок, связанных с именем.

traceC’An error occurred: » + е. message);

traceCPlease specify a valid name.»);

В приведенном коде, если метод setName ( ) сгенерирует исключение Virtu alPetExcessDataException, будет выполнен первый блок catch. Если метод сгенерирует исключение VirtualPetlnsufficientDataException, будет выполнен второй блок catch. И наконец, если метод сгенерирует исключение VirtualPetNameException, будет выполнен третий блок catch. Обратите внимание, что в блоках catch сначала перечислены специфические типы данных ошибок, а затем — общие. При возникновении исключения выполняется тот блок catch, у которого первым совпадет тип данных параметра с типом данных исключения.

Таким образом, если мы изменим тип данных параметра первого блока catch на тип VirtualPetNameException, первый блок catch будет выполняться для всех трех типов исключений!

Вспомните, что класс VirtualPetNameException является суперклассом для обоих классов VirtualPetlnsufflcientDataException и VirtualPetExcessDataException, поэтому считается, что они соответствуют типу данных VirtualPetNameException.

Фактически мы могли бы предотвратить выполнение всех блоков catch, разместив первым новый блок catch, типом данных параметра которого является Error:

try {

b. setName(«некоеИмяЖивотного»); } catch (e:Error) {

// Обрабатываем все ошибки. Никакие другие блоки catch

// выполняться не будут.

Руководство по actionscript. часть 2, стр. 086

TraceC’An error occurred:» + е. message);

traceC’The first catch block handled the error.»); } catch (e:VirtualPetExcessDataException) {

// Обработка ситуации «слишком длинное».

traceC’An error occurred: » + e. message);

traceCPlease specify a shorter name.»); } catch (e:\ZirtualPetInsufficientDataException) {

// Обработка ситуации «слишком короткое».

traceC’An error occurred: » + e. message);

traceCPlease specify a longer name.»); } catch (e:VirtualPetNameException) {

// Обработка общих ошибок, связанных с именем.

traceC’An error occurred: » + е. message);

traceCPlease specify a valid name.»);

}

Очевидно, что попытка добавить первый блок catch в предыдущем коде обречена на провал, но этот пример иллюстрирует иерархическую природу обработки ошибок. Поместив базовый блок catch в самое начало списка обработчиков, мы можем обработать все ошибки в одном блоке. И наоборот, если поместить базовый блок catch в конец списка, мы можем создать «страховочную сетку», которая будет обрабатывать любые ошибки, не «пойманные» предыдущими блоками catch. Например, в следующем коде последний блок catch будет выполнен только в том

случае, если блок try сгенерирует исключение, которое не принадлежит типам данных VirtualPetExcessDataException, Virtual Pet In sufficient Data Exception или VirtualPetNameException:

try {

b. setName(«некоеИмяЖивотного»); } catch (e:VirtualPetExcessDataException) {

// Обработка переполнения.

Руководство по actionscript. часть 2, стр. 087

TraceC’An error occurred: » + e. message);

traceCPlease specify a smaller value.»): } catch (e:VirtualPetlnsufficientDataException) {

// Обработка нулевой длины.

traceC’An error occurred: » + e. message);

traceCPlease specify a larger value.»); } catch (e:VirtualPetNameException) {

// Обработка общих ошибок, связанных с размерностью.

traceC’An error occurred: » + е. message);

traceCPlease specify a valid dimension.»); } catch (e:Error) {

// Обработка любых ошибок, которые не относятся

// к ошибкам VirtualPetNameException.

}

Не забывайте, что выбор степени детализации ошибок зависит от ситуации. Реализуя вариант 4, мы создали пользовательские подклассы класса Error для каждого исключения, генерируемого классом VirtualPet. Этот подход дает нашей программе максимальную возможность независимо обрабатывать различные типы ошибок. Однако во многих ситуациях подобная гибкость является излишней. Будет лучше, если степень детализации ошибок будет определяться требованиями логики вашей программы.

Передача исключений вверх по иерархии объектов

В ActionScript исключение может быть сгенерировано в любом месте программы, даже в сценарии кадра на временной шкале! В этом случае возникает вопрос: каким образом среда выполнения Flash находит соответствующий блок catch для обработки этого исключения? И что произойдет при отсутствии блоков catch? Эти загадки решаются с. помощью магии передачи исключений вверх по иерархии объектов. Проследуем по пути передачи исключений вместе со средой Flash с того момента, как она выполнит в программе оператор throw. В ходе последующей инсценировки «размышления» среды выполнения Flash оформлены в виде комментариев.

Руководство по actionscript. часть 2, стр. 088

После исполнения оператора throw нормальная работа программы немедленно прекращается и среда Flash пытается найти блок try, который содержит этот оператор. Например, рассмотрим оператор throw:

// Среда выполнения Flash: Хм. Оператор throw.

// Существует ли блок try, который содержит этот оператор?

throw new Error(«Something went wrong»);

Если оператор throw включен в блок try, среда выполнения Flash пытается найти блок catch, тип данных параметра которого совпадает с типом данных значения сгенерированного исключения (в данном случае с типом Error):

// Среда выполнения Flash: Отлично, я нашла блок try. // Существует ли соответствующий блок catch? try {

throw new Error(«Something went wrong»);

}

Если соответствующий блок catch найден, среда выполнения Flash передает управление программой этому блоку:

try {

throw new Error(«Something went wrong»); // Среда выполнения Flash: Найден блок catch, типом данных параметра // которого является Error! Поиск завершен. Сейчас я выполню этот // блок catch… } catch (e:Error) {

// Обработка ошибок…

}

Однако если соответствующий блок catch не может быть найден или если оператор throw изначально не был включен в блок try, среда Flash проверяет, размещен ли этот оператор внутри метода или функции. Если да, то среда выполнения ищет блок try вокруг кода, вызвавшего этот метод или функцию. Следующий код демонстрирует, как среда Flash реагирует на оператор throw, который размещен внутри метода и не включен в блок try:

public function doSomething ( ):void { // Среда выполнения Flash: Хм. Блок try отсутствует. // Проверю, кто вызвал этот метод, throw new Error(«Something went wrong»);

}

Если код, вызвавший этот метод или функцию, включен в блок try, среда Flash попытается найти соответствующий блок catch и, если такой блок будет найден, выполнит его. Следующий код демонстрирует исключение, генерируемое в методе и обрабатываемое там, где вызывается этот метод (то есть уровнем выше по стеку вызовов):

public class ProblemClass { public function doSomething ( ):void { // Среда выполнения Flash: Хм. Блок try отсутствует. // Проверю-ка я, кто вызвал этот метод, throw new Error(«Something went wrong»);

}

}

// Среда выполнения Flash: Ага, вот кто вызвал метод doSomething( ). // И вот блок try, включающий этот код, вместе с блоком catch, типом // данных параметра которого является Error! Моя работа сделана. // Блок catch, пожалуйста, выполняйтесь… try {

var problemObject:ProblemClass = new ProblemClass( ); problemObject. doSomething( ); } catch (e:Error) { // Обработка ошибок…

Руководство по actionscript. часть 2, стр. 089

Trace(«Exception caught in ErrorDemo, thrown by doSomething( ).»);

}

}

Стек вызовов — это список функций или методов программы, исполнением которых среда А щ Flash занимается в любой момент времени. Функции и методы размещаются в списке 3-У в порядке, обратном порядку их вызова, по направлению сверху вниз. Если функция

находится непосредственно под другой функцией в стеке вызовов, значит, нижняя

функция была вызвана верхней функцией. Самая нижняя функция в стеке вызовов — это

функция, выполняемая в настоящий момент.

В приложении Flex Builder и среде разработки Flash вы можете использовать отладчик для просмотра стека вызовов текущей программы, как описано в документации корпорации Adobe.

В предыдущем коде исключение, сгенерированное методом, было поймано блоком try/catch, в который включена инструкция вызова метода. Тем не менее, если вокруг кода, вызывающего функцию или метод, не найден блок try, среда выполнения Flash просматривает весь стек вызовов в поисках блока try с соответствующим блоком catch. Следующий код демонстрирует метод, генерирующий ошибку, которая обрабатывается двумя уровнями выше в стеке вызовов:

public class ProblemClass { public function doSomething ( ):void { // Среда выполнения Flash: Хм. Блок try отсутствует.^ // Проверю-ка я, кто вызвал этот метод, throw new Error(«Something went wrong»):

}

public class NormalClass { public function NormalClass ( ) { // Среда выполнения Flash: Ага, вот кто вызвал метод doSomething( ). // Но здесь все равно нет блока try. Проверю,

// кто вызвал этот метод,

var problemObject:ProblemClass = new ProblemClass( ); problemObject. doSomething( );

}

}

// Среда выполнения Flash: Ага! Нашла блок try, который имеет блок // catch, типом данных параметра которого

// является Error! Моя работа сделана.



Полезные ссылки
Случайные записи
  • 10.03.2011">Руководство по actionscript. часть 4, стр. 035
  • 04.03.2011">Руководство по actionscript. часть 5, стр. 038
  • 06.03.2011">Руководство по actionscript. часть 4, стр. 132
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.126
  • 19.02.2013">Избавление от шлаков и токсинов
  • 06.03.2011">Руководство по actionscript. часть 4, стр. 146
  • 15.03.2011">Руководство по actionscript. часть 3, стр. 047
  • 26.02.2011">Руководство по actionscript. часть 6, стр. 051
  • 21.03.2011">Руководство по actionscript. часть 2, стр. 055
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.87
  • 02.03.2011">Руководство по actionscript. часть 5, стр. 093
  • 25.02.2011">Руководство по actionscript. часть 6, стр. 090
  • 13.06.2010">Самоучитель по креативному веб-дизайну. Книга 4, стр.83
  • 18.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.83
  • 28.02.2011">Руководство по actionscript. часть 6, стр. 013
Опрос

Какие цвета вы предпочитаете?

View Results

Loading ... Loading ...