DarkGoodWIN - Рефакторинг. Зачем?

Тут можно читать онлайн DarkGoodWIN - Рефакторинг. Зачем? - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming, год 2013. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Рефакторинг. Зачем?
  • Автор:
  • Жанр:
  • Издательство:
    неизвестно
  • Год:
    2013
  • ISBN:
    нет данных
  • Рейтинг:
    4.63/5. Голосов: 81
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 100
    • 1
    • 2
    • 3
    • 4
    • 5

DarkGoodWIN - Рефакторинг. Зачем? краткое содержание

Рефакторинг. Зачем? - описание и краткое содержание, автор DarkGoodWIN, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Рефакторинг. Зачем? - читать онлайн бесплатно полную версию (весь текст целиком)

Рефакторинг. Зачем? - читать книгу онлайн бесплатно, автор DarkGoodWIN
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Заведём для этого в каждом классе функцию HitTest , которая будет возвращать True в случае, если наша точка находится внутри графического примитива и False в противном случае:

type

TCircle = class(TObject)

public

X: Integer;

Y: Integer;

D: Integer;

function HitTest(aX, aY: Integer): Boolean;

end;

type

TRectangle = class(TObject)

public

X1: Integer;

Y1: Integer;

X2: Integer;

Y2: Integer;

function HitTest(X, Y: Integer): Boolean;

end;

function TCircle. HitTest(aX, aY: Integer): Boolean;

begin

Result:= Sqrt(Sqr(X — aX) + Sqr(Y — aY)) <= D;

end;

function TRectangle. HitTest(X, Y: Integer): Boolean;

begin

Result:= (X1 <= X) and (X <= X2) and (Y1 <= Y) and (Y <= Y2);

end;

Это была реализация классов, а тут реализация базовой функции HitTest, которая должна проверить все наши объекты:

var

Circles: array of TCircle;

Rectangles: array of TRectangle;

function HitTest(X, Y: Integer): Boolean;

var

I: Integer;

begin

Result:= False;

for I:= 0 to Length(Rectangles) — 1 do

begin

Result:= Rectangles[I].HitTest(X, Y);

if Result then

Exit;

end;

for I:= 0 to Length(Circles) — 1 do

begin

Result:= Circles[I].HitTest(X, Y);

if Result then

Exit;

end;

end;

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

В чём тут смысл? Вместо нескольких массивов для каждого графического примитива отдельно, мы заводим класс, который описывает графический примитив, назовём его, например, TShape. Далее мы хотим хранить все наши примитивы, независимо от их типа в массиве «Shapes: array of TShape». Но так просто у нас это не получится, компилятор ругнётся, что типы не совместимы.

Для того, чтобы мы смогли положить наши прямоугольники и круги в массив TShape , нам надо поменять их наследование. Заменим TObject на TShape в объявлении класса:

type

TShape = class(TObject)

end;

TCircle = class(TShape)

public

…..

end;

TRectangle = class(TShape)

public

…..

end;

Теперь наш круг одновременно и круг и графический примитив, равно как и в действительности. То же самое можно сказать и о квадрате. Что это значит с точки зрения программирования? То, что класс TCircle , наследник класса TShape можно использовать везде, где можно использовать класс TShape. Более того, все переменные и методы класса TShape (кроме private) будут также доступны в классе TCircle .

Не буду сильно углубляться в теорию, всё–таки я предпочитаю объяснять на примерах, поэтому сразу перейдём к тому как изменится наша функция с попмощью этого нехитрого преобразования:

var

Shapes: array of TShape;

function HitTest(X, Y: Integer): Boolean;

var

I: Integer;

begin

Result:= False;

for I:= 0 to Length(Shapes) — 1 do

begin

if Shapes[I] is TCircle then

Result:= (Shapes[I] as TCircle).HitTest(X, Y)

else if Shapes[I] is TRectangle then

Result:= (Shapes[I] as TRectangle).HitTest(X, Y)

if Result then

Exit;

end;

end;

На самом деле тоже не очень красиво. Приходится для каждого примитива делать проверку, поддерживает–ли он нужный нам тип (оператор is ) и осуществлять приведение типов (оператор as ). Операторы is и as предназначены для работы только с объектами и не работают с простыми типами. Подробнее о них можно прочитать в документации.

Чтобы оценить мощь наследования нам остался всего один шаг. В класс TShape добавим строку «function HitTest(X, Y: Integer): Boolean; virtual; abstract;”, а в классы TCircle и TRectangle добавим после аналогичных строчек ключевое слово override :

type

TShape = class(TObject)

public

function HitTest(X, Y: Integer): Boolean; virtual; abstract;

end;

TCircle = class(TShape)

public

…..

function HitTest(X, Y: Integer): Boolean; override;

end;

TRectangle = class(TShape)

public

…..

function HitTest(X, Y: Integer): Boolean; override;

end;

Что это означает? Мы как бы говорим, что класс TShape в принципе может проверить, попали в него координаты мыши или нет, но конкретная реализация зависит от того, какой именно примитив используется. То есть абстрактно функциональность есть, но её реализация должна быть переопределена в классах потомках.

Нашу многострадальную функцию теперь можно переписать так:

var

Shapes: array of TShape;

function HitTest(X, Y: Integer): Boolean;

var

I: Integer;

begin

Result:= False;

for I:= 0 to Length(Shapes) — 1 do

begin

Result:= Shapes[I].HitTest(X, Y);

if Result then

Exit;

end;

end;

При этом, в случаю кругов, в реальности будет вызываться функция TCircle. HitTest , а в случае прямоугольников — TRectangle. HitTest .

Понятно, что в случае с одной абстрактной функцией выигрышь не совсем очевиден, но ведь можно расширить базовый класс, добавив в него функции:

TShape. Move(dx, dy: Integer); virtual; abstract;

для перемещения примитива,

TShape. Rotate(x, y: Integer; angel: Double); virtual; abstract;

для поворота вокруг точки,

TShape. Flip(Line: TLine); virtual; abstract;

для зеркального отображения вокруг прямой.

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

Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


DarkGoodWIN читать все книги автора по порядку

DarkGoodWIN - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Рефакторинг. Зачем? отзывы


Отзывы читателей о книге Рефакторинг. Зачем?, автор: DarkGoodWIN. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x