Отмечу, что на практике, глядя на исходный код, часто возникает потребность понять, что можно сделать с тем или иным классом. Так вот, значительно проще, удобнее и быстрее пройтись по членам класса, чем найти все функции, принимающие класс в качестве параметра.
И немного из терминологии. Функцию член класса принято называть методом. В нашем случае, мы имеем класс с одним методом CalculateLineLength .
В прошлой главе мы создали первый метод. Он вычисляет длину отрезка. На современных машинах это вычисление занимает совсем немного времени, однако, предположим, что действие это не такое быстрое и для каждой линии выполняется многократно.
Есть много способов решения подобной проблемы, но один из самых простых и универсальных — это кэширование.
Действительно, зачем считать длину каждый раз, если это можно сделать единожды, запомнить посчитанное значение и потом, в качестве результата функции, возвращать его.
Вот как это могло бы выглядеть:
type
TLine = class(TObject)
public
X1: Integer;
Y1: Integer;
X2: Integer;
Y2: Integer;
LengthCalculated: Boolean;
LineLength: Double;
function CalculateLineLength: Double;
end;
function TLine. CalculateLineLength: Double;
begin
if not LengthCalculated then
begin
LineLength:= Sqrt(Sqr(X2 — X1) + Sqr(Y2 — Y1));
LengthCalculated:= True;
end;
Result:= LineLength;
end;
При всей иллюзии работоспособности, в данном коде присутствует целый спектр проблем. Во–первых, тому, кто будет использовать класс снаружи, будет неочевидно, что необходимо вызывать функцию CalculateLineLength и не корректно напрямую использовать поле LineLength . Ну а во–вторых — нет механизма пересчёта длины при изменении координат точек.
Первую проблему мы решим в этой главе, а вторую оставим для следующей, так как для её решения потребуется познакомиться с ещё одним термином.
Мы уже упоминали, да и не раз сталкивались с ключевым словом public, теперь пришло время рассказать, что оно означает. Члены класса, объявленные как public доступны как внутри класса, так и за его пределами.
Кроме public, есть ещё и ключевое слово private, которое означает, что члены класса доступны только из методов данного класса и не доступны за его пределами. В Object Pascal реализации, используемой в компиляторе Delphi, у данной функциональности есть особенность. Видимость private распространяется не только на членов класса, но и на весь модуль, в котором объявлен класс, что является неким отклонением от общих принципов, но уж так сложилось исторически, ничего не попишешь.
Так или иначе, private члены классов — это некие служебные поля и методы (переменные и функции), не предназначенные для использования за пределами класса.
Давайте посмотрим, как будет выглядеть декларация нашего класса, если мы унесём в private секцию всё лишнее:
type
TLine = class(TObject)
private
LengthCalculated: Boolean;
LineLength: Double;
public
X1: Integer;
Y1: Integer;
X2: Integer;
Y2: Integer;
function CalculateLineLength: Double;
end;
Данная реализация вполне себе красноречиво говорит, что поля LengthCalculated и LineLength трогать не надо. По крайней мере, если вы не планируете менять внутренней логики класса.
Для того, чтобы можно было каким–то образом реагировать на изменения значений полей классов, были придуманы свойства (property). Они так же могут перекликаться с понятиями getter и setter .
Сначала я приведу пример кода, а потом поясню что происходит. Думаю так будет понятнее:
type
TLine = class(TObject)
private
LengthCalculated: Boolean;
LineLength: Double;
FX2: Integer;
FY2: Integer;
FX1: Integer;
FY1: Integer;
procedure SetX1(const Value: Integer);
procedure SetX2(const Value: Integer);
procedure SetY1(const Value: Integer);
procedure SetY2(const Value: Integer);
public
property X1: Integer read FX1 write SetX1;
property Y1: Integer read FY1 write SetY1;
property X2: Integer read FX2 write SetX2;
property Y2: Integer read FY2 write SetY2;
function CalculateLineLength: Double;
end;
function TLine. CalculateLineLength: Double;
begin
if not LengthCalculated then
begin
LineLength:= Sqrt(Sqr(X2 — X1) + Sqr(Y2 — Y1));
LengthCalculated:= True;
end;
Result:= LineLength;
end;
procedure TLine. SetX1(const Value: Integer);
begin
LengthCalculated:= False;
FX1:= Value;
end;
procedure TLine. SetX2(const Value: Integer);
Читать дальше