С названием свойства и типов данных все понятно — на их месте мы напишем Perimeter и double соответственно. А вот про Getter и Setter нужно поговорить немного подробнее.
[note]Getter — Название метода (обязательно функция) или поля данного класса, которое будет возвращать значение при попытке получить значение от данного property. В случае использования метода — значение будет возвращаться методом-функцией, в случае поля — значение будет доставаться из поля. Используемый метод или поле должны обязательно существовать в классе, иметь описание и реализацию. Тип возвращаемый методом или полем должен обязательно соответствовать типу, указанному в объявлении property в классе.
В случае с реализацией метода в качестве Getter`а появляется возможность каким-то образом модифицировать возвращаемые данные, производить дополнительную обработку или совершить какие-либо изменения в самом экземпляре объекта, т.к. Getter в этом случае — это обыкновенный метод. Главное, чтобы он возвращал значение, как и обычная процедура.[/note]
[note]Setter — Название метода-процедуры данного класса, которая будет устанавливать значение, переданное ей в качестве единственного параметра Value, в какое-либо существующее поле. Само присвоение может быть реализовано любым образом, оно описывается в этом методе по усмотрению программиста. А сам метод должен обязательно содержать единственный параметр с именем Value и с типом, который соответствует типу property. Setter позволяет, например, предварительно преобразовать данные, прежде чем их куда-то присваивать, хотя их даже присваивать куда-то необязательно. Все зависит от цели использования property. Возможно setter просто производит какие-то взаимодействия с полями класса, и эти взаимодействия как-то зависят от переданных в property данных.[/note]
Наверное, вы уже догадались, для чего мы реализовывали методы TTriangle.GetPerimeter и TTriangle.SetPerimeter, потому что они являются самыми классическими примерами Getter`а и Setter`а. Метод GetPerimeter отвечает за возврат значения периметра во внешний код при обращении, а SetPerimeter устанавливает периметр треугольника, имея при этом параметр Value, поделенное на три значение которого затем присваивает сторонам треугольника. Посмотрим, как же будет выглядеть наше свойство (property):
1
2
3
4
5
6
7
8
9
10
11
12
13
|
TTriangle = class
private
function GetPerimeter: double;
procedure SetPerimeter(Value: double);
public
a, b, c: double;
property Perimeter: double read GetPerimeter write SetPerimeter;
function Square: double;
constructor Create(NewA, NewB, NewC: double);
end;
|
Вот и все, наш property успешно создан!
[important]Прошу обратить внимание на то, что свойства объявляются после объявления полей и перед объявлением методов! И да, почему же наши методы GetPerimeter и SetPerimeter, являющиеся Getter`ом и Setter`ом для свойства Perimeter, мы поместили в область доступа private? А затем, что теперь доступ нам к этим методам из внешнего кода не понадобится, их функциональные возможности теперь можно использовать посредством свойства Perimeter. Их можно и даже нужно скрыть. А нужно их скрыть еще и потому, что при объявлении свойства требуется, чтобы используемые при этом поля и методы были объявлены ранее. А т.к. методы нельзя объявлять перед property (они объявляются после всех property), то удобнее будет поместить группу доступа private выше группы доступа public. Хотя этот побочный эффект можно обойти, но в нашем случае этого делать не нужно.[/important]
Рассмотрим простой пример работы с новым классом и нашим первым свойством:
1
2
3
4
5
6
7
8
9
10
|
procedure TForm1.FormCreate(Sender: TObject);
var
t: TTriangle;
begin
t := TTriangle.Create(10, 11, 12);
t.Perimeter := 30; // Присваиваем периметр посредством property.
// Соответственно будет выполнен Setter (SetPerimeter) и присвоено значение сторонам треугольника
ShowMessage('Стороны треугольника: '+FloatToStr(t.a)+';'+FloatToStr(t.b)+';'+FloatToStr(t.c)+' Периметр: '+FloatToStr(t.Perimeter));
// Здесь мы опять обращаемся к property Perimeter, это свойство вызывает Getter GetPerimeter, которое и возвращает нам значение
end;
|
Хотелось бы немного заострить внимание на том, что в качестве Getter`а может выступать и поле (которое тоже помещено в private). В этом случае при обращении к значению свойства будет возвращено значение этого поля. При этом Setter может, например устанавливать значение в это скрытое поле, предварительно его обработав, к примеру, если в Setter предусмотрена передача значения в сантиметрах, а поле Getter хранит в себе значение в метрах. Т.е. потребуется сначала провести в Setter`е тривиальное преобразование.
[tip]В описании свойства можно, например, не указывать Getter или Setter. Тогда мы получим в результате свойство, доступное только для записи или чтения соответственно. Выглядеть описания тогда будут так:
1
2
|
property Perimeter: double read GetPerimeter; // Возможно только чтение из property
property Perimeter: double write SetPerimeter; // Возможно только присвоение в property
|
Свойства в Delphi имеют еще много различных форм объявлений и работы, но пока многие из них выходят за рамки изученных нами тем, да и к тому же редко используются на практике.
В этом уроке мы рассмотрели свойства (property) в Delphi, которые позволяют реализовать логику обработки данных перед присваиванием значения или перед возвращением значения.
|