12168

Свойства в Delphi

Лекция

Информатика, кибернетика и программирование

Свойства Понятие свойства Помимо полей и методов в объектах существуют свойства. При работе с объектом свойства выглядят как поля: они принимают значения и участвуют в выражениях. Но в отличие от полей свойства не занимают места в памяти а операции их чтения и записи а

Русский

2013-04-24

83 KB

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

Методы получения и установки значений свойств

Методы получения (чтения) и установки (записи) значений свойств подчиняются определенным правилам. Метод чтения свойства — это всегда функция, возвращающая значение того же типа, что и тип свойства. Метод записи свойства — это обязательно процедура, принимающая параметр того же типа, что и тип свойства. В остальных отношениях это обычные методы объекта. Примерами методов чтения и записи свойств являются методы GetItemCount и SetActive в классе TDelimitedReader:

type

 TDelimitedReader = class

   FActive: Boolean;

   ...

   procedure SetActive(const AActive: Boolean);

   function GetItemCount: Integer;

   ...

   property Active: Boolean read FActive write SetActive;

   property ItemCount: Integer read GetItemCount;

 end;

Использование методов для получения и установки свойств позволяет проверить корректность значения свойства, сделать дополнительные вычисления, установить значения зависимых полей и т.д. Например, в методе SetActive вполне целесообразно осуществить проверку состояния файла (открыт или закрыт), чтобы избежать его повторного открытия или закрытия:

procedure TDelimitedReader.SetActive(const AActive: Boolean);

begin

 if Active <> AActive then // Если состояние изменяется

 begin

   if AActive then

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

   else

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

   FActive := AActive;     // Сохранение состояния в поле

 end;

end;

Наличие свойства Active позволяет нам отказаться от использования методов Open и Close, традиционных при работе с файлами. Согласитесь, что открывать и закрывать файл с помощью свойства Active гораздо удобнее и естественнее. Одновременно с этим свойство Active можно использовать и для проверки состояния файла (открыт или нет). Таким образом, для осуществления трех действий требуется всего лишь одно свойство! Это делает использование Ваших классов другими программистами более простым, поскольку им легче запомнить одно понятие Active, чем, например, три метода: Open, Close и IsOpen.

Значение свойства может не храниться, а вычисляться при каждом обращении к свойству. Примером является свойство ItemCount, значение которого вычисляется как Length(FItems).

Свойства-массивы

Кроме обычных свойств в объектах существуют свойства-массивы (array properties). Свойство-массив — это индексированное множество значений. Например, в классе TDelimitedReader множество элементов, выделенных из считанной строки, удобно представить в виде свойства-массива:

type

 TDelimitedReader = class

   ...

   FItems: array of string;

   ...

   function GetItem(Index: Integer): string;

   ...

   property Items[Index: Integer]: string read GetItem;

 end;

function TDelimitedReader.GetItem(Index: Integer): string;

begin

 Result := FItems[Index];

end;

Элементы массива Items можно только читать, поскольку класс TDelimitedReader предназначен только для чтения данных из файла.

В описании свойства-массива разрешено использовать только методы, но не поля. В этом состоит отличие свойства-массива от обычного свойства.

Основная выгода от применения свойства-массива — возможность выполнения итераций с помощью цикла for, например:

var

 Reader: TDelimitedReader;

 I: Integer;

...

 for I := 0 to Reader.ItemCount - 1 do

   Writeln(Reader.Items[I]);

...

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

Свойства-массивы имеют два важных отличия от обычных массивов:

их индексы не ограничиваются диапазоном и могут иметь любой тип данных, а не только Integer. Например, можно создать свойство-массив, в котором индексами будут строки. Обращение к такому свойству могло бы выглядеть примерно так:

Reader.Items['FirstName'] := 'Alexander';

операции над свойством-массивом в целом запрещены; разрешены операции только с его элементами.

Свойство-массив как основное свойство объекта

Свойство-массив можно сделать основным свойством объектов данного класса. Для этого в описание свойства добавляется слово default:

type

 TDelimitedReader = class

   ...

   property Items[Index: Integer]: string read GetItem; default;

   ...

 end;

Такое объявление свойства Items позволяет рассматривать сам объект класса TDelimitedReader как массив и опускать имя свойства-массива при обращении к нему из программы, например:

var

 R: TDelimitedReader;

 I: Integer;

...

 for I := 0 to R.ItemCount - 1 do

   Writeln(R[I]);

...

Следует помнить, что только свойства-массивы могут быть основными свойствами объектов; для обычных свойств это недопустимо.

Методы, обслуживающие несколько свойств

Один и тот же метод может использоваться для получения (установки) значений нескольких свойств одного типа. В этом случае каждому свойству назначается целочисленный индекс, который передается в метод чтения (записи) первым параметром.

В следующем примере уже известный Вам метод GetItem обслуживает три свойства: FirstName, LastName и Phone:

type

 TDelimitedReader = class

   ...

   property FirstName: string index 0 read GetItem;

   property LastName: string index 1 read GetItem;

   property Phone: string index 2 read GetItem;

 end;

Обращения к свойствам FirstName, LastName и Phone заменяются компилятором на вызовы одного и того же метода GetItem, но с разными значениями параметра Index:

var

 Reader: TDelimitedReader;

...

 Writeln(Reader.FirstName); // Эквивалентно: Writeln(Reader.GetItem(0));

 Writeln(Reader.LastName);  // Эквивалентно: Writeln(Reader.GetItem(1));

 Writeln(Reader.Phone);     // Эквивалентно: Writeln(Reader.GetItem(2));

...

Обратите внимание, что метод GetItem обслуживает как свойство-массив Items, так и свойства FirstName, LastName и Phone. Удобно, не правда ли!

Перед тем, как перейти к более сложным понятиям ООП, приведем полную реализацию класса TDelimitedReader. Настоятельно рекомендуем Вам внимательно ознакомиться с этой реализацией, поскольку в ней сведено воедино все то, о чем говорилось в предыдущих разделах.

type

 TDelimitedReader = class

   // Поля

   FFile: TextFile;

   FItems: array of string;

   FActive: Boolean;

   FDelimiter: Char;

   // Методы чтения и записи свойств

   procedure SetActive(const AActive: Boolean);

   function GetItemCount: Integer;

   function GetEndOfFile: Boolean;

   function GetItem(Index: Integer): string;

   // Методы

   procedure PutItem(Index: Integer; const Item: string);

   function ParseLine(const Line: string): Integer;

   function NextLine: Boolean;

   // Конструкторы и деструкторы

   constructor Create(const FileName: string; const ADelimiter: Char = ';');

   destructor Destroy; override;

   // Свойства

   property Active: Boolean read FActive write SetActive;

   property Items[Index: Integer]: string read GetItem; default;

   property ItemCount: Integer read GetItemCount;

   property EndOfFile: Boolean read GetEndOfFile;

   property Delimiter: Char read FDelimiter;

 end;

{ TDelimitedReader }

constructor TDelimitedReader.Create(const FileName: string;

 const ADelimiter: Char = ';');

begin

 AssignFile(FFile, FileName);

 FActive := False;

 FDelimiter := ADelimiter;

end;

destructor TDelimitedReader.Destroy;

begin

 Active := False;

end;

function TDelimitedReader.GetEndOfFile: Boolean;

begin

 Result := Eof(FFile);

end;

function TDelimitedReader.GetItem(Index: Integer): string;

begin

 Result := FItems[Index];

end;

function TDelimitedReader.GetItemCount: Integer;

begin

 Result := Length(FItems);

end;

function TDelimitedReader.NextLine: Boolean;

var

 S: string;

 N: Integer;

begin

 Result := not EndOfFile;

 if Result then             // Если не достигнут конец файла

 begin

   Readln(FFile, S);        // Чтение очередной строки из файла

   N := ParseLine(S);       // Разбор считанной строки

   if N <> ItemCount then

     SetLength(FItems, N);  // Отсечение массива (если необходимо)

 end;

end;

function TDelimitedReader.ParseLine(const Line: string): Integer;

var

 S: string;

 P: Integer;

begin

 S := Line;

 Result := 0;

 repeat

   P := Pos(Delimiter, S);  // Поиск разделителя

   if P = 0 then            // Если разделитель не найден, то считается, что

     P := Length(S) + 1;    // разделитель находится за последним символом

   PutItem(Result, Copy(S, 1, P - 1)); // Установка элемента

   Delete(S, 1, P);                    // Удаление элемента из строки

   Result := Result + 1;               // Переход к следующему элементу

 until S = '';                         // Пока в строке есть символы

end;

procedure TDelimitedReader.PutItem(Index: Integer; const Item: string);

begin

 if Index > High(FItems) then    // Если индекс выходит за границы массива,

   SetLength(FItems, Index + 1); // то увеличение размера массива

 FItems[Index] := Item;          // Установка соответствующего элемента

end;

procedure TDelimitedReader.SetActive(const AActive: Boolean);

begin

 if Active <> AActive then // Если состояние изменяется

 begin

   if AActive then

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

   else

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

   FActive := AActive;     // Сохранение состояния в поле

 end;

end;


 

А также другие работы, которые могут Вас заинтересовать

54342. Методические основы использования прикладного ПО на уроках в школе 111.5 KB
  Деление на группы производят либо по способностям либо случайным образом например по партам или по алфавиту. В этом случае как правило формируются разно уровневые группы в которых быстро определяются лидеры и аутсайдеры. Гузеев предложил различать группы выравнивания поддержки и развития. Группы выравнивания состоят из учащихся с различной успеваемостью и ориентированы на достижение всех ее участников обязательного уровня образования; группы поддержки однородны по успеваемости; в группах развития ученики более высокого уровня...
54343. Дмитриу Донской. Куликовская битва 83 KB
  Что позволило Дмитрию Ивановичу открыто выступить против монголотатар и разгромить их 12 октября 1350 года у московского удельного князя Ивана родился сын которого окрестили Дмитрием. Дмитрия Московского сумели получить для своего князя ярлык. Разведка великого князя донесла что Мамай собрав войско уже три недели ждал на Дону Ягайло Литовского.
54344. Сучасний урок - джерело творчості вчителя 2.78 MB
  €œТестові завдання з геометрії. клас із використанням тестуючого комплексу MIFTests. Кожен вчитель є справжнім керівником дитячого колективу діти визнають своїх педагогів за лідерів та активно співпрацюють із ними а це означає: вчитель має власний педагогічний імідж свій особливий педагогічний почерк він – конкурентоспроможний компетентний фахівець. МАТЕМАТИКА ТА ІТК У сучасному світі потреба в комп’ютерних технологіях постійно зростає – вони необхідні і вдома і на робочому місці. Систематичне використання...
54345. Комплекс игр и упражнений «Биоэнергопластика» в коррекционной работе с детьми-логопатами 717 KB
  Поражение верхней височной извилины приводит к тому что человек слышит слова но не понимает их смысла так как в зоне Вернике как в своеобразной картотеке хранятся все усвоенные человеком слова точнее их звуковые образы и он всю жизнь пользуется этой картотекой. Если произошло поражение этой зоны то хранящиеся там звуковые образы слов распадаются человек перестает понимать слова. При нормальном слухе он остается глухим к словам. Действительно левое полушарие отвечает: за движение правых конечностей и обеих рук за...
54346. Урок русского языка и литературного чтения 352 KB
  Планируемые результаты учебного предмета Русский язык общие на 4 года обучения Личностными результатами изучения русского языка в начальной школе являются: осознание языка как основного средства человеческого общения; восприятие русского языка как явление национальной культуры; понимание того что правильная устная и письменная речь является показателем индивидуальной культуры человека; способность к самооценке на основе наблюдения за собственной речью; способность к итоговому и пооперационному самоконтролю; ...
54347. Етапи розвязування задач за допомогою компютера 1.3 MB
  Для розвязання цих задач компютер озброєний найрізноманітнішим програмним забезпеченням, яке поділяється на чотири великих категорії: операційні системи, системні утиліти, системи програмування, прикладне програмне забезпечення.
54348. Інформаційно-комп’ютерні технології на уроках географії та природознавства 83.5 KB
  Вчителями природознавства опановано такі теми: Створення слайдових презентацій у середовищі програми MS Power Point Пошук та завантаження текстової звукової та відеоінформації з Інтернету Створення потокових презентацій відео кліпів у середовищі програми Movie Mker Створення та обробка графічної інформації засобами растрового графічного редактора dobe Photoshop. № п п Термін Тема заняття 1 Вересень Створення слайдових презентацій у середовищі програми MS Power Point. 3 Лютий Створення потокових презентацій відео кліпів у...
54349. Методика вивчення дробових чисел за курсом Математика у 5-6 класах 334 KB
  Організація самостійної діяльності учнів при вивченні дій ззвичайними дробами. ВСТУП Характеристика обовязкових результатів навчальних досягнень при вивченні дробових чисел Основною метою курсу математики 5-6 класів вважається: систематичний розвиток понять числа та вироблення вмінь усно та письмово робити арифметичні операції над числами формувати вміння переводити практичні задачі на мову математики підготовка учнів до вивчення курсів Алгебра€ та Геометрія€. Форми організації усного рахунку Добре розвинені у учнів навики усної...
54350. Методика организации инновационной деятельности в школе 142.5 KB
  Внутренние мотивы таковы: интерес к процессу деятельности интерес к результату деятельности стремление к саморазвитию развитию какихлибо своих качеств способностей. Мотив придает смысл деятельности для человека. Проведение диагностики: Изучение мотивов трудового поведения Ваш творческий потенциал Личностные ориентации педагога Готовность педагога к работе в инновационном режиме наблюдения за работой учителя индивидуальные собеседования дали возможность заинтересовать 76 педагогов нашей школы в участии в инновационной...