Как уже упоминалось ранее, основная задача свойств - организация доступа к внутренним полям объекта. Простейший вид взаимодействия свойства и соответствующего ему поля называется прямым доступом (direct access). Предыдущий пример (с автомобилем) как раз демонстрирует использование прямого доступа при организации операций чтения/записи. Здесь любое изменение значения свойства Speed сразу передается в поле fSpeed. Но на практике применение идеи прямого доступа, скорее, является исключением из правил.
При проектировании нового компонента вы имеете уникальную возможность еще на стадии разработки оказать услугу программистам, которые воспользуются вашим творением. Каким образом? Вернемся к нашему TNewAutomobile и его свойству Speed. Любой автомобиль имеет максимальный предел скорости, а в нашем случае пользователь может поместить в поле fSpeed значение, превышающее скорость света. Каким образом устранить ошибку? Для этого необходимо описать методы, контролирующие операции чтения и записи.
type
TNewAutomobile = class(TCustomControl) private
fSpeed: cardinal;
procedure SetSpeed(Value:cardinal); //установка значения в поле function GetSpeed : cardinal; //чтение значения из поля
published
property Speed: cardinal read GetSpeed write SetSpeed; end;
Метод, отвечающий за запись, всегда является процедурой и, как правило, обладает единственным параметром. Второй параметр понадобится только при работе со свойством типа массив. В качестве параметра Value внутреннему полю объекта передается новое значение. Процедура проверяет корректность вводимых данных и в случае успеха присваивает полю новое значение.
procedure TNewAutomobile.SetSpeed(Value:cardinal); begin
if Value<=300 then fSpeed:=Value else ShowMessage('Недопустимое значение'); end;
Метод, отвечающий за чтение, всегда оформляется в виде функции, которой не передаются параметры. Единственным исключением будут функции, осуществляющие чтение из свойства типа массив (в этом случае потребуется параметр, определяющий индекс элемента в массиве) и чтение с использованием команды index. Результат, возвращаемый функцией, должен иметь такой же тип, как и у соответствующего свойства.
function TNewAutomobile.GetSpeed : cardinal; begin
Result:=fSpeed; end;
Для проверки корректности вводимых данных операция записи значения скорости реализуется при помощи процедуры SetSpeed(). Этот метод не пропустит значений выше 300 км/ч. Чтение также осуществляется с использованием внутреннего метода будущего компонента - функции GetSpeed() .
Согласно существующим соглашениям имена процедур, отвечающих за запись значений в поле, должны начинаться с приставки Set. Имена функций, обеспечивающих чтение, - с приставки Get. Вторая часть имени включает название свойства, с которым работают эти методы, например SetSpeed(), GetSpeed().
Реализуемый внутри класса способ доступа к его внутренним полям базируется на одном из фундаментальных понятий ООП - инкапсуляции. Вы как создатель нового компонента скрываете от программиста (который в дальнейшем воспользуется вашим компонентом) всю внутреннюю структуру объекта. Да, в общем-то, ему и дела нет до того, что происходит внутри вашего творения; главное, чтобы не было ошибок.
Классификация свойств
В Delphi различают пять типов свойств (табл. 16.1), каждый из которых обладает своими особенностями объявления и организации доступа.
Наиболее часто встречающееся свойство у компонентов Delphi. Может быть числовым, строковым или символьным. Допускается непосредственное редактирование значений этих свойств. Примером простых свойств являются: Caption, Text, Tag, Left, Top.
Свойства перечислимого типа разрешают выбор значения только из списка, предопределенного разработчиком компонента. Кроме того, в качестве перечислимых могут выступать свойства логического типа. Примером таких свойств являются: Color, DragKind, DragMode, FormStyle. Признаком перечислимого свойства в Инспекторе объектов является появление ниспадающего списка с допустимыми значениями справа от имени свойства.
В Инспекторе объектов рядом с именем свойства типа множество установлен символ « + ». В качестве примера такого свойства может выступить свойство формы Borderlcons. Двойной щелчок по свойству разворачивает в Инспекторе объектов дополнительные строки, изменяя значения которых пользователь определяет состав множества. Множество допускается редактировать и вручную путем изменения его состава внутри квадратных скобок в строке ввода.
Компонент в качестве свойства может содержать другой класс или объект. Как и в случае свойства типа Set, слева от имени свойства в Инспекторе объектов имеется символ «+», но теперь вместо квадратных скобок вы увидите имя класса. Примером свойств типа объект являются: Font, HorzScrollBar, VertScrollBar.
Свойство типа массив может принимать любой тип данных, определенный в Инспекторе объектов, и обозначается в Инспекторе объектов кнопкой с многоточием (свойства Items, Lines).
®По секрету от Borland открою вам еще одну тайну: обработчик события также является свойством, но особым - процедурного типа.
Простые свойства
В соответствии с названием создание простых свойств несложно. Из приведенного ниже листинга видно, что в секции частных объявлений указаны три поля объекта: целочисленное, строковое и символьное. Для обеспечения доступа к этим полям в секции published объявлены три соответствующие свойства. Если такой компонент окажется на форме, то внешний вид Инспектора объектов будет соответствовать. Обратите внимание, что помимо наших свойств в Инспекторе объектов отображены свойства, унаследованные от родительского класса TCustomControl.
Имейте в виду, что в ниспадающем списке Инспектора объектов возможные значения перечислимого свойства отображаются не в той последовательности, в которой были описаны в листинге, а в алфавитном порядке.
Свойство типа множество
Преимущество использования свойства типа множество над другими типами свойств заключается в предоставляемой возможности одновременного выбора нескольких значений из состава множества.