Показать сообщение отдельно
Старый 14.03.2008, 20:53
Iv вне форума Посмотреть профиль Отправить личное сообщение для Iv Посетить домашнюю страницу Iv Найти все сообщения от Iv
  № 28  
Iv
 
Аватар для Iv

Регистрация: Apr 2001
Адрес: Moscow
Сообщений: 1,475
По умолчанию Рефакторинг intersect2Lines

Я напомню цель текущего шага: удаление случаев скрытого нетипизированного доступа.
Следующей мишенью наших действий станет метод Math2.intersect2Lines. Этот случай очень похож на предыдущий. Но, как я и обещал, чтобы разнообразить наш инструментарий способ рефакторинга будет выбран иной.

Вырежем и вставим метод в класс LineSVG, сделаем его публичным. Сохраним оба документа (CTRL+SHIFT+S). Используя панель Problems перейдем на строку с ошибкой и добавим "LineSVG." перед вызовом метода.

Поскольку мы намерены избавиться от скрытого нетипизированного доступа в аргументах метода, для начала снизим зависимость кода метода от аргументов.
В самом начале метода объявим два объекта first и second типа LineSVG и создадим их используя аргументы метода.
Везде далее в коде заменим использование аргументов на доступ через объекты LineSVG.
Теперь аргументы используются только для создания объектов LineSVG, чего мы и добивались.

Сделаем метод не статическим: удаляем static из объявления метода. Сохраняем документ, переходим на ошибку используя панель Problems. Создаем экземпляр LineSVG и от его имени вызываем метод intersect2Lines:
Код AS3:
var startArm : LineSVG = new LineSVG(point1, control1);
var s:Point = startArm.intersect2Lines (point1, control1, control2, point2);
Поскольку данные startArm мы можем получить в классе LineSVG, удаляем два первых аргумента в вызове intersect2Lines. Затем переходим на метод и в нем также удаляем два первых аргумента. Подсвечиваются ошибки в объявлении first, удаляем эту строку. Затем удаляем все обращения к first, поскольку сейчас это текущий объект.
Заменим аргументы на один: second : LineSVG и удалим в теле метода объявление second.
Перейдем на ошибки в методе getQuadBez_RP.
Скопируем строку объявления startArm, переименуем переменную в endArm и скопируем параметры из вызова метода intersect2Lines. После этого параметры заменим на endArm.
В результате наших действий имя метода перестало отражать его суть. Переименуем в getLineIntersection и исправим вызов метода.
В итоге, измененная чать метода Math2.getQuadBez_RP будет выглядеть так:
Код AS3:
var startArm : LineSVG = new LineSVG(point1, control1);
var endArm : LineSVG = new LineSVG(control2, point2);
var s:Point = startArm.getLineIntersection(endArm);
Имя аргумента метода getLineIntersection - second, больше не отражает сути. Переименуем в target.

Удалим объявления временных переменных ссылающихся на существующие значения.Подробно процесс на примере:
- закомментируем строку var x1 : Number = start.x;
- скопируем start.x в буфер обмена;
- выделим первую ошибку: обращение к x1;
- CTRL+F, ставим фокус в поле Replace With, CTRL+V, в нем должна появиться строка "start.x";
- отмечаем чек боксы Case Sensitive и Whole Word
- жмем Replace All
Впрочем, вам возможно будет удобнее заменить выделением и вставкой.

Далее также поступаем с переменными y1, x4, y4 и получаем такой код:
Код AS3:
public function getLineIntersection(target : LineSVG) : Point {
	var dx1 : Number = end.x - start.x;
	var dx2 : Number = target.start.x - target.end.x;
 
	if (!(dx1 || dx2)) return null;
 
	var m1 : Number = (end.y - start.y) / dx1;
	var m2 : Number = (target.start.y - target.end.y) / dx2;
 
	if (!dx1) {
		return new Point(start.x, m2 * (start.x - target.end.x) + target.end.y);
	} else if (!dx2) {
		return new Point(target.end.x, m1 * (target.end.x - start.x) + start.y);
	}
	var xInt : Number = (-m2 * target.end.x + target.end.y + m1 * start.x - start.y) / (m1 - m2);
	var yInt : Number = m1 * (xInt - start.x) + start.y;
	return new Point(xInt, yInt);
}
Теперь мы можем более осознанно подойти к именованию временных переменных.
Заменяем dx1 на currentDistanceX, а dx2 на targetDistanceX, исправляя подсвечивающиеся ошибки сразу после каждого переименования. Пробуем поставить const вместо var. Ошибок нет, так и оставим.

Идем дальше вниз по коду. Добавляем фигурные скобки блоку if. Думайте что хотите, но я уверен, что if без фигурных скобок снижает читабельность кода, а пользы никакой.

В вычислении переменных m1 и m2 видим, что используются вычисления, аналогичные currentDistanceX и targetDistanceX.
Объявим аналогичные локальные константы currentDistanceY и targetDistanceY и присвоим им соответствующие значения скопировав из вычислений. Затем заменим вычисления на эти константы:
Код AS3:
const currentDistanceY : Number = end.y - start.y;
const targetDistanceY : Number = target.start.y - target.end.y;
 
var m1 : Number = currentDistanceY / currentDistanceX;
var m2 : Number = targetDistanceY / targetDistanceX;
Значение переменных стало куда очевиднее: это отношение высоты к ширине габаритного прямоугольника отрезков. Отношение высоты к ширине это тангенс. Переименовываем и делаем константами.
Код AS3:
const currentTangent : Number = currentDistanceY / currentDistanceX;
const targetTangent : Number = targetDistanceY / targetDistanceX;
Дальше по коды мы только переименуем переменные xInt и yInt на intersectionX и intersectionY и сделаем их константами. Остановимся на этом, ибо нет предела совершенству.
В итоге имеем вот такой метод:
Код AS3:
public function getLineIntersection(target : LineSVG) : Point {
	const currentDistanceX : Number = end.x - start.x;
	const targetDistanceX : Number = target.start.x - target.end.x;
 
	if (!(currentDistanceX || targetDistanceX)) { 
		return null;
	}
	const currentDistanceY : Number = end.y - start.y;
	const targetDistanceY : Number = target.start.y - target.end.y;
 
	const currentTangent : Number = currentDistanceY / currentDistanceX;
	const targetTangent : Number = targetDistanceY / targetDistanceX;
 
	if (!currentDistanceX) {
		return new Point(start.x, targetTangent * (start.x - target.end.x) + target.end.y);
	} else if (!targetDistanceX) {
		return new Point(target.end.x, currentTangent * (target.end.x - start.x) + start.y);
	}
	const intersectionX : Number = (-targetTangent * target.end.x + target.end.y + currentTangent * start.x - start.y) / (currentTangent - targetTangent);
	const intersectionY : Number = currentTangent * (intersectionX - start.x) + start.y;
	return new Point(intersectionX, intersectionY);
}
Тестируем код, радуемся, что всё получилось.
Потому, что программировать не надо бояться, программировать радоваться надо.

А если серьезно, то обратите внимание на то, что мы уже довольно давно работаем с кодом, но до сих пор так и не вникали в суть его логики. Более того, если вы обратили внимание, в процессе рефакторинга код понемногу сам нам рассказывает о себе.
__________________
http://realaxy.com


Последний раз редактировалось iNils; 20.12.2010 в 13:25.