![]() |
Исправление ошибки
Вначале проанализируем ошибку.
Переменная hasRotate объявлена в методе с типом Boolean, а в строке кода, которая дает ошибку, ей присваивается значение int. Далее мы смотрим как используется эта переменная. Мы не будем доверять нашей внимательности, а пройдемся поиском по коду. Ищем вхождения слова "hasRotate" начиная со строки с ошибкой. Вхождение лишь одно и оно совсем рядом с ошибочной строкой. Это еще одна удача: изменения, которые сделаем будут локальны. Смотрим, как используется переменная: с ее помощью производится проверка на наличие вхождений слова rotate. В принципе, в таких случаях есть два пути: либо создание новой переменной и дальнейшая работа уже с ней, либо изменение кода таким образом, чтобы переменная использовалась правильно. К первому решению чаще прибегают в случае, если изменение логики дальнейшей проверки нежелательно или затруднительно. Поскольку способ решения выбирается исходя из критерия минимального внесения изменений и у нас нет показаний за первое решение, поэтому прибегнем ко второму. Продублируем две строки, начиная со строки с ошибкой, одну пару закомментируем и пока оставим на память. Вторую строку изменим. Вот, что у меня получилось: Код AS3:
Обратите внимание на еще один момент: хотя логика вполне прозрачна, и мы могли бы вместо > -1 использовать, например != -1 или придумать что-нибудь еще, мы оставляем использованный автором способ, поскольку остальной код пока для нас - потемки и абсолютно быть уверенным в правоте своих действий невозможно. По этой же причине мы оставляем закомментированные строки с исходным кодом. На этом процедура исправления ошибки заканчивается, и мы можем вернуться к рефакторингу. |
Продолжаем рефакторинг класса PathToArray
Вложений: 1
Для того, чтобы решить что делать дальше, откройте в FDT панель Problems и отсортируйте по столбцу Resource.
Здесь мы видим два типа ошибок: Local Variable is never used (локальная переменная никогда не используется) Untyped member access (нетипизированный доступ к членам) Первая ошибка встречается лишь однажды: двойным кликом по соответствующей строке в панели Problems переходим на строку с ошибкой в коде и удаляем ее. В итоге у нас останутся только ошибки нетипизированного доступа. Просмотрев код видим, что ошибки вызваны нетипизированными обращениями к переменным объектов fill, stroke, firstP, lastP, lastC. Первые два объявлены как переменные класса, остальные как локальные переменные метода makeDrawCmds. Начнем с локальных переменных. Судя по их использованию в коде, они могут быть типизированы как Point. Попробуем заменить тип на Point в их объявлении. После замены типов и сохранения документа количество ошибок резко уменьшилось и изменился их тип на "You can not assign an 'Object' to a 'Point'". Заменим, вот пример замены: Было: Код AS3:
Код AS3:
Затем, кликая по образовавшимся у скроллера красным меткам ошибок, я переходил на очередную строку с ошибкой и заменял закрывающую фигурную скобку на обычную и удалял "y:". В итоге, количество ошибок типизации в классе снизилось до шести. Все они - обращения к переменным объектов fill и stroke. В отличие от предыдущего шага, у этих объектов отсутствует соответствие в родных классах Flash и нам потребуется создать собственные. Сразу за самой последней закрывающей фигурной скобкой документа создадим внутренние классы. Затем зададим им публичные поля, одноименные с теми, доступ к которым осуществляется из объектов fill и stroke. Добавим в конструкторы соответствующие аргументы. Вот, что у меня получилось: Код AS3:
Код AS3:
Здесь способ ускорения процесса правки несколько иной. Перейдя на начало документа, используем сочетание клавиш CTRL+1. FDT - умница, он хоть и не может решить всех проблем, но он предлагает добавить кастинг соответствующего типа. Соглашаемся, после чего добавляем ключевое слово new и удаляем имена полей и фигурные скобки. было: Код AS3:
Код AS3:
Код AS3:
Закончив, выделим двойным кликом Fill проверяем, везде ли расставлено ключевое слово new. То же самое проделываем со Stroke. В результате наших действий, в классе PathToArray не должно остаться ни одной подсвечивающейся ошибки. Тестируем, убеждаемся в том, что Flash-компилятор не ругается, а изображение рисуется. Итоговый класс аттачу к этому посту. |
Небольшое отступление
Возможно, читатель думает, что я портировал проект, отрефакторил и оптимизировал и теперь, зная все подводные камни, веду их по спланированному сюжету.
Это не так. Я не знаю, к чему мы придем. Я вначале делаю небольшой шаг, затем описываю что сделал. Всё по-честному. - Что же мне дает уверенность в том, что в итоге всё получится хорошо? - Ну, помимо природной наглости, я понимаю, что так или иначе удастся справиться с возникающими вопросами, а также я придерживаюсь простых правил, которые мне помогут:
|
Приводим в порядок Math2
При поверхностной оценке здесь, в отличие от предыдущих классов, может возникнуть необходимость изменения типа данных аргументов.
Следовательно, этот шаг затронет не только текущий класс, но и другие, его использующие. Этот шаг мы оставим на самый последний момент. Сейчас мы нацелены на снижение количества подсвечиваемых ошибок и первое, что стоит сделать - заняться локальными переменными. Идем сверху вниз. ratioTo - пропускаем intersect2Lines - задаем всем аргументам тип Object - задаем всем локальным переменным тип Number rotation - задаем всем аргументам тип Number midPt - задаем аргументам тип Number - указываем возвращаемое значение Object getQuadBez_RP - здесь не указаны типы аргументов, для того, чтобы выяснить поиском по файлам (CTRL+H, File Search) ищем вызовы этого метода и, констатируя факт, указываем использованные типы: Код AS3:
- задаем тип Number переменным dx и dy - остальным переменным задаем тип Object bezierSplit - задаем всем аргументам тип Number - задаем переменной m тип Function pointOnCurve - задаем всем аргументам тип Number - видим, что можем легко избавиться от подсвечивания ошибки нетипизированного доступа и заменяем процесс создания объекта на такой: Код AS3:
- задаем всем аргументам тип Number pointsOnLine - задаем всем аргументам тип Number - задаем переменной i тип int - задаем всем остальным переменным тип Number curveApproxLen - задаем всем аргументам тип Number; Первая часть на этом заканчивается, причем на мажорной ноте: если вы обратите внимание на панель Problems, то увидите, что число ошибок стало меньше 100 и это означает, что окончание процесса не за горами. |
удаляем Object
Следующим нашим шагом борьбы с нетипизированным доступом станет повсеместное удаление типа Object.
Изучив код, увидим, что очень часто Object используется там, где бы мог использоваться Point. Порядок замены в таких случаях:
|
Взглянув на код, определяем какие методы нам проще всего изменить. Внешним признаком будет служить нам то, что в качестве аргументов и возвращаемого значения не применяется тип Object.
Единственный подходящий метод - curveApproxLen. Добавим в методе создание новой точки, назовем ее middle: Код AS3:
Тут же видим: вызываемый метод pointOnCurve подходит для следующего шага, поскольку у него только возвращаемое значение имеет тип Object. Заменяем объект и возвращаемый тип на Point: Код AS3:
Для того, чтобы найти места в коде, где используется метод pointOnCurve применим хитрость: переименуем pointOnCurve в pointOnCurve1, сохраним классс и по списку ошибок увидим где это. Результат - два вызова в этом же классе. Проще всего исправить curveApproxLen. Мы просто ставим вызов метода pointOnCurve вместо new Point(...) и удаляем строку объявления объекта mp. Также можем удалить "Math2." в вызове. В итоге должны получить вот такой метод: Код AS3:
Теперь можно разобраться со вторым методом, использующим pointOnCurve, это метод pointsOnCurve. Сейчас он возвращает массив точек и... драма! Неприятная неожиданность: мы обнаруживаем, что это не могут быть объекты класса Point, поскольку в этом методе задается точке загадочная переменная r. Ну, что-ж, это не критично. Cоздадим подкласс объекта Point. Пока мы не знаем как его называть, поскольку сущность переменной r нам неизвестна. Мы только видим, что это угол, но угол чего именно на этом этапе мы выяснять не имеем права. Второй вопрос - нам следует выяснить будут ли использованы эти точки вне класса Math2, чтобы определиться делать ли новый класс публичным или достаточно будет internal. Для этого переименуем pointsOnCurve в pointsOnCurve1, сохраним документ и пройдемся по полученым ошибкам - местам вызова этого метода. К моему удивлению - ни одной ошибки. Включаем занудство и используя поиск по файлам ищем вхождение строки "pointsOnCurve". Опять ничего кроме его самого. Делаем вывод: мы нашли неиспользуемый метод. Тревога отменяется, закомментируем этот метод полностью и идем дальше. Среди оставшихся четырех методов содержащих ошибки только bezierSplit в качестве параметров не требует Object, поэтому заглянем в него. Этот метод использует другой метод из этого же класса: midPt. Переходим на него и видим, что возвращаемый тип можно заменить на Point, что и делаем. По прежней схеме с переименованием проверим, а не используется ли он где-то еще. Но в этот раз заодно зададим имя без сокращений: midpoint. А поскольку снаружи текущего класса этот метод нигде не используется, то сделаем его приватным. В итоге, он должен выглядеть так: Код AS3:
Ошибок нет, можно продолжить доработку метода bezierSplit. Заменим вызовы метода midpoint через локальную переменную m на обычный вызов и удалим строку объявления этой переменной. Это требуется для того, чтобы убедиться в правильности передаваемых аргументов. Далее, всем объектам, которым присваивается возвращаемое методом midpoint значение зададим тип Point. Но стоит ли на этом останавливаться? Если мы оставим тип Object переменным p1 и p2, то в возвращаемом объекте будет каша. Да, мы не знаем и пока не хотим знать логику приложения, но здравый смысл подсказывает, что p1 и p2 должны иметь такой-же как и у остальных тип - Point. Прислушаемся к голосу разума, исправим, и получим вот такой метод: Код AS3:
Ошибок нет, идем дальше. Я взялся за ratioTo, но переименовав его обнаружил, что он также нигде не используется. Проверил поиском - подтвердилось. Закомментируем и идем дальше. |
Выбирая из оставшихся двух переименованием, обнаруживаем, что метод intersect2Lines используется только в этом классе и лишь в одном месте. Делаем метод приватным.
Наиболее предсказуемые последствия возникнут если сейчас изменить возвращаемый тип. Логика подсказывает, что пересечение двух линий - точка. Заменяем возвращаемый тип на Point. Редактор тут же подсвечивает ошибки: возврат NaN и Object. В первом случае заменяем на null, во втором случае на new Point(...) - в трех местах. После этого двойным кликом выделяем имя метода и используя CTRL+R открываем панель результатов поиска и там переходим на метод getgetQuadBez_RP и заменяем тип переменной s на Point. (Можно заодно удалить Math2. в вызове метода intersect2Lines) Далее приведем в порядок аргументы метода intersect2Lines, задав им тип Point. После этого в панели Problems отсортируем список по полю Description так, чтобы вверху оказались строки "You can not assign an 'Object' to an 'Point'" и приступим к исправлению этих ошибок. Здесь нужно четко понимать: наша задача в данный момент - исправить только эти ошибки, а не весь проект. Наши исправления должны носить по возможности локальный характер. Поэтому поступим следующим образом: - переименуем первый аргумент в point1; - перед вызовом intersect2Lines объявляем переменную p1 с типом Point и присваиваем ей новый объект Point, которому в качестве параметров передаем point1.x и point1.y; - поступаем аналогично со следующим аргументом, задав ему имя control1. - аналогично изменяем оставшиеся два аргумента, имеющие тип Object. - сохраняем проект, тестируем. Вот что имеем на данный момент: Код AS3:
Мы имеем возможность быстро протестировать изменения и, если придется откатиться, то совсем недалеко. Это огромное преимущество маленьких шагов. Итак, в настоящий момент все ошибки типизации сконцентрировались в одном методе: getQuadBez_RP и разбиты на две группы: ошибки вызванные неверной типизацией аргументов и ошибки вызванные объектом halves. Следуя нашей стратегии вначале исправим ошибки, затрагивающие только методы текущего класса. Объект halves - это возвращаемый методом bezierSplit объект, содержащий в себе два других объекта b0 и b1, каждый из которых содержит в себе по 4 объекта типа Point. У нас есть выбор: либо создать пользовательский класс для типизации объекта halves, либо, поскольку его структура жестко задана, использовать массив и последующую типизацию. В данном случае массив предпочтительнее, поскольку это более короткий и логичный путь. Название метода (bezierSplit - разделить безье) и использованное имя переменной, которой присваивается возвращаемое значение (halves - половинки), также говорят за использование массива. Ок, пойдем этим путем. Проверим вначале на какие другие методы окажут воздействие изменения в bezierSplit. Сделать это можно либо переименовав его, либо с помощью CTRL+R. Метод используется только в getQuadBez_RP. Это заодно нам позволяет сделать его приватным. Далее: - изменяем возвращаемый методом bezierSplit тип на Array; - изменяем строку return на: Код AS3:
- изменяем присвоение переменным b0 и b1 на доступ к 0 и 1 элементам массива соответственно; - тестируем. Аналогичным образом поступаем с объектами в возвращаемом методом bezierSplit массиве - также делаем из них массивы: Код AS3:
- чтобы увидеть все вхождения b0 и b1, а также сделать код более читабельным, переименовываем эти переменные в bezier0 и bezier1 соответственно. - дублируем строки, в которых появились ошибки, одну пару комментируем, чтобы не забыть что было изначально; - в тех местах где подсветились ошибки заменяем имена переменных и доступ к их содержимому на оператор доступа к массиву. Замена производится соответственно: ".p1" на "[0]", ".c1" на "[1]", ".c2" на "[2]", ".p2" на "[3]". Наример, было: b0.c1 стало: bezier0[1]; Результат должен получиться таким: Код AS3:
|
вторая часть рефакторинга getQuadBez_RP
Эту часть процесса мы будем делать исходя из очень простой логики действий: вначале вызываем ошибку, затем исправляем.
Изменяем первый тип аргумента метода getQuadBez_RP на тип Point. Сохраняем документ. В панели Properties появляется список ошибок вида: "You can not assign an 'Object' to an 'Point'" Двойным кликом переходим на первую ошибку и заменяем первый аргумент в вызове метода Math2.getQuadBez_RP с объекта на new Point(...). Сохраняем документ, чтобы обновилась панель Problems. Переходим к следующей ошибке этого типа. Исправляем таким образом все ошибки данного типа. Обязательно тестируем. Результатом этого процесса должно стать полное отсутствие ошибок в панели Problems. Это и было целью первого этапа рефакторинга. Мы ее добились и на этом этап можно считать законченным. |
В процессе вы познакомились с различными приемами и принципами решения проблем.
Я и дальше постараюсь применять разные подходы к исправлению схожих задач, чтобы максимально охватить их спектр, даже, если в каком-то конкретном случае решение будет не самым оптимальным. В дальнейшем вы сами владея этими инстурументами сможете выбирать подходящий. Подведем некоторые итоги. Мы добивались того, чтобы в FDT не показывались ошибки. Но мы не прятали их, а именно исправляли. Результатом этого стало то, что кроме коллекции цветов в проекте не осталось объектов типа Object, а это - один из критериев оценки. - Но устраивает ли нас код в текущем состоянии? - Ни в коем случае. Этот код нам непонятен, его повторное использование практически невозможно, внесение изменений в код крайне затруднительно. Собственно именно поэтому мы и говорим об окончании первой волны рефакторинга, но это - только начало. |
Удаление ненужных методов
Вложений: 1
Перед началом следующего этапа почистим код: нужно отыскать и удалить неиспользуемые методы.
Раньше этого не стоило делать: мы пока не можем быть уверены в том, что в других частях проекта эти методы не использованы (имеется ввиду вторая часть - анимация отрисовки svg файла), а возвращаться в последствии к этапу приведения типов не хочется. Удалив лишнее нам проще будет сконцентрироваться на оставшихся методах и сэкономит время. При этом, разумеется, у нас должна остаться копия проекта в текущем состоянии для того, чтобы при необходимости мы могли восстановить любой удаленный метод. Неиспользуемые методы я рекомендую именно удалить, а не просто закомментировать, поскольку отстутствие лишнего кода, в том числе и закомментированного, ускорит процесс нашей работы. Мы уже удаляли методы, так что я не буду концентрироваться на самой процедуре, отмечу лишь тот момент, что удаление одного метода может повлечь за собой прекращение необходимости в другом. Также напоминаю, что удаление метода в незнакомом проекте требует обязательного последующего тестирования. В итоге ненужные методы оказались только в классе Math2 и там, после удаления осталось их всего 4: getQuadBez_RP - публичный, я его переместил в начало класса; intersect2Lines - приватный; midpoint - приватный; bezierSplit - приватный; Чтобы "сверить наши часы" я выкладываю файлы проекта в текущем состоянии. |
| Часовой пояс GMT +4, время: 15:45. |
Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.