Библиотека knigago >> Литература по изданиям >> Самиздат, сетевая литература >> Рефакторинг. Зачем?

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

Рефакторинг. Зачем?
Книга - Рефакторинг. Зачем?.   DarkGoodWIN  - прочитать полностью в библиотеке КнигаГо
Название:
Рефакторинг. Зачем?
DarkGoodWIN

Жанр:

Самиздат, сетевая литература, Литература ХXI века (эпоха Глобализации экономики), Программирование: прочее, Pascal, Delphi, Lazarus и т.п.

Изадано в серии:

неизвестно

Издательство:

неизвестно

Год издания:

ISBN:

неизвестно

Отзывы:

Комментировать

Рейтинг:

Поделись книгой с друзьями!

Помощь сайту: донат на оплату сервера

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

Аннотация к этой книге отсутствует.

Читаем онлайн "Рефакторинг. Зачем?". [Страница - 8]

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

Для доступа к приватным полям снаружи — предусмотрены свойства. Строка «property X1: Integer read FX1 write SetX1;” означает, что мы свойство X1, при чтении которого будет возвращаться значение FX1 (то, что после ключевого слова read), а при записи — будет вызываться функция SetX1 (то, что после ключевого слова write).

Таким образом, запись: «X:= Line. X1» эквивалентна записи «X:= Line. FX1», а запись «Line. X1:= X» эквивалентна записи «Line. SetX1(X)».

Наследование

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


type

TCircle = class(TObject)

public

X: Integer;

Y: Integer;

D: Integer;

end;


TRectangle = class(TObject)

public

X1: Integer;

Y1: Integer;

X2: Integer;

Y2: Integer;

end;

Круг вполне описывается координатами центра (X, Y) и диаметром (D), а прямоугольник — двумя точками (X1, Y1 и X2, Y2).

Допустим у нас есть программа для рисования кругов и прямоугольников. Каждый раз, когда мы рисуем новый круг, он кладётся в массив Circles: array of TCircle, а когда рисуем новый прямоугольник, он кладётся в массив Rectangles: array of TRectangle.

Далее нам нужен код, который определит, находится–ли заданная координата внутри одного из нарисованных примитивов. Например, пользователь совершил клик мыши и нам нужно выделить приметив, если кликнули именно на него.

Заведём для этого в каждом классе функцию 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

--">

Оставить комментарий:


Ваш e-mail является приватным и не будет опубликован в комментарии.