Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Основы программирования на Delphi.doc
Скачиваний:
0
Добавлен:
01.01.2020
Размер:
5.09 Mб
Скачать

3.5. Методы

Процедуры и функции, предназначенные для выполнения над объектами действий, называются методами. Предварительное объявление методов выполняется при описании класса в секции interface модуля, а их программный код записывается в секции implementation. Однако в отличие от обычных процедур и функций заголовки методов должны иметь уточненные имена, т.е. содержать наименование класса. Приведем возможную реализацию одного из методов в классе TDelimitedReader:

procedure TDelimitedReader.SetActive(const AActive: Boolean);

begin

if AActive then

Reset(FileVar) // Открытие файла

else

CloseFile(FileVar); // Закрытие файла

end;

Обратите внимание, что внутри методов обращения к полям и другим методам выполняются как к обычным переменным и подпрограммам без уточнения экземпляра объекта. Такое упрощение достигается путем использования в пределах метода псевдопеременной Self (стандартный идентификатор). Физически Self представляет собой дополнительный неявный параметр, передаваемый в метод при вызове. Этот параметр и указывает экземпляр объекта, к которому данный метод применяется. Чтобы пояснить сказанное, перепишем метод SetActive, представив его в виде обычной процедуры:

procedure TDelimitedReader_SetActive(Self: TDelimitedReader;

const AActive: Boolean);

begin

if AActive then

Reset(Self.FileVar) // Открытие файла

else

CloseFile(Self.FileVar); // Закрытие файла

end;

Согласитесь, что метод SetActive выглядит лаконичнее процедуры TDelimitedReader_SetActive.

Практика показывает, что псевдопеременная Self редко используется в явном виде. Ее необходимо применять только тогда, когда при написании метода может возникнуть какая-либо двусмысленность для компилятора, например при использовании одинаковых имен и для локальных переменных, и для полей объекта.

Если выполнить метод SetActive,

Reader.SetActive(True);

то обрабатываемый файл будет открыт. При этом неявный параметр Self будет содержать значение переменной Reader. Такой вызов реализуется обычными средствами процедурного программирования приблизительно так:

TDelimitedReader_SetActive(Reader, True);

3.6. Свойства

3.6.1. Понятие свойства

Помимо полей и методов в объектах существуют свойства. При работе с объектом свойства выглядят как поля: они принимают значения и участвуют в выражениях. Но в отличие от полей свойства не занимают места в памяти, а операции их чтения и записи ассоциируются с обычными полями или методами. Это позволяет создавать необходимые сопутствующие эффекты при обращении к свойствам. Например, в объекте Reader присваивание свойству Active значения True вызовет открытие файла, а присваивание значения False — закрытие файла. Создание сопутствующего эффекта (открытие или закрытие файла) достигается тем, что за присваиванием свойству значения стоит вызов метода.

Объявление свойства выполняется с помощью зарезервированного слова property, например:

type

TDelimitedReader = class

...

FActive: Boolean;

...

// Метод записи (установки значения) свойства

procedure SetActive(const AActive: Boolean);

property Active: Boolean read FActive write SetActive; // Свойство

end;

Ключевые слова read и write называются спецификаторами доступа. После слова read указывается поле или метод, к которому происходит обращение при чтении (получении) значения свойства, а после слова write — поле или метод, к которому происходит обращение при записи (установке) значения свойства. Например, чтение свойства Active означает чтение поля FActive, а установка свойства — вызов метода SetActive. Чтобы имена свойств не совпадали с именами полей, последние принято писать с буквы F (от англ. field). Мы в дальнейшем также будем пользоваться этим соглашением. Начнем с того, что переименуем поля класса TDelimitedReader: поле FileVar переименуем в FFile, Items — в FItems, а поле Delimiter — в FDelimiter.

type

TDelimitedReader = class

// Поля

FFile: TextFile; // FileVar -> FFile

FItems: array of string; // Items -> FItems

FActive: Boolean;

FDelimiter: Char; // Delimiter -> FDelimiter

...

end;

Обращение к свойствам выглядит в программе как обращение к полям:

var

Reader: TDelimitedReader;

IsOpen: Boolean;

...

Reader.Active := True; // Эквивалентно Reader.SetActive(True);

IsOpen := Reader.Active; // Эквивалентно IsOpen := Reader.FActive

Если один из спецификаторов доступа опущен, то значение свойства можно либо только читать (задан спецификатор read), либо только записывать (задан спецификатор write). В следующем примере объявлено свойство, значение которого можно только читать.

type

TDelimitedReader = class

...

FItems: array of string;

...

function GetItemCount: Integer;

...

property ItemCount: Integer read GetItemCount; // Только для чтения!

end;

function TDelimitedReader.GetItemCount: Integer;

begin

Result := Length(FItems);

end;

Здесь свойство ItemCount показывает количество элементов в массиве FItems. Поскольку оно определяется в результате чтения и разбора очередной строки файла, пользователю объекта разрешено лишь узнавать количество элементов.

В отличие от полей свойства не имеют адреса в памяти, поэтому к ним запрещено применять операцию @. Как следствие, их нельзя передавать в var- и out-параметрах процедур и функций.

Технология объектно-ориентированного программирования в среде Delphi предписывает избегать прямого обращения к полям, создавая вместо этого соответствующие свойства. Это упорядочивает работу с объектами, изолируя их данные от непосредственной модификации. В будущем внутренняя структура класса, которая иногда является достаточно сложной, может быть изменена с целью повышения эффективности работы программы. При этом потребуется переработать только методы чтения и записи значений свойств; внешний интерфейс класса не изменится.