Есть такая концепция - "отделение реализации от интерфейса". Интерфейс - это то, с чем работает пользователь, реализация - то,
как это работает. Например, в автомобиле: пользователь жмет педаль, в двигатель подается больше топлива, автомобиль едет быстрее. В самолете пилот не жмет педаль, а тянет ручку, но эффект тот же - ускорение. В данном случае педаль и ручка - это свойства (интерфейсы), а системы подачи топлива - это реализации (методы SetProp). В принципе, ничто не мешает переставить педаль газа в самолет, и тогда пользователь, привыкший к одному способу управления, будет переучиваться быстрее и не заметит изменения реализации. Понятно, что в реальности замена пилота водителем автомобиля чревата последствиями, но если абстрагироваться от этих деталей, мы увидим следущее: есть цепочка интерфейс (педаль) - реализация (двигатель) - результат (ускорение). Если вдруг возникнет необходимость изменить реализацию (не ехать, а лететь), не меняя интерфейса, то свойства - самое подходящее для этого средство. Например:
- Код: Выделить всё
interface
TCar = class // Это машина
private
FKoef: integer;
FPedal: integer;
FSpeed: integer;
protected
procedure SetPedal(const AValue: integer); virtual; // реализация. virtual означает, что потомки класса могут изменять эту реализацию, а могут и не изменять
published
property Pedal: integer read FPedal write SetPedal; // Положение педали
property Speed: integer read FSpeed; //Скорость. Пользователь не может менять ее напрямую
property Koef: integer read FKoef; // Коэффициент ускорения, выражающий зависимость скорости от положения педали. Задается конструкцией автомобиля, то есть в конструкторе ;)
constructor Create; // Тут выделяется память и задаются всякие конструктивные особенности
end;
{ TPlane }
TPlane = class (TCar)
private
FFlyingHeight: integer; //В этих переменных все и хранится
FFlyingSpeed: integer;
FHeightKoef: integer;
protected
procedure SetPedal(const AValue: integer); override; // меняем реализацию педали, не меняя самой педали
published
property FlyingSpeed: integer read FFlyingHeight;
property HeightKoef: integer read FHeightKoef; // У самолета в конструкции заложена еще и зависимость высоты полета от скорости
end;
implementation
{ Tcar }
// Собственно реализация
procedure TCar.SetPedal(const AValue: integer); // AValue - новое значение
begin
if FPedal=AValue then exit; // если ничего не меняется - на выход
FPedal:=AValue; // Сохраняем новое значение
FSpeed:=FPedal*FKoef; //Задаем скорость
end;
{ TPlane }
// реализация самолета
procedure TPlane.SetPedal(const AValue: integer);
begin
// Поскольку скорость и педаль никуда не делись, вызываем унаследованный метод их задания (кстати, у самолета будет другой коэффициент ускорения, который должен быть задан в конструкторе - унаследованный метод это учтет):
inherited SetPedal(AValue);
// Но у самолета добавилась высота - изменяем ее:
FFlyingHeight:=FPedal*FHeightKoef;
end;
Такая реализация гарантирует, что значение положения педали и соответствующей скорости движения всегда взаимосвязаны - прямо как в настоящей машине.
В VCL в методах типа SetProterty еще вызываются обработчики событий - специальные процедуры, оповещающие пользователя об изменениях.
Вот так в общих чертах это и работает.