На этом шаге мы рассмотрим делегирование методов.
Указатели на методы описываются так же, как процедурные типы, которые рассмотрены в шаге 32. Единственным отличием является указание ключевых слов of object после списка формальных параметров. При этом директива дальнего вызова не требуется ни для 16-ти, ни для 32-х разрядной версий Delphi.
type TMyMethod = procedure (Sender : Object) of object;
Для демонстрации общих черт и отличий работы с процедурными типами и типами методов приведем пример, в котором используются те же функции, что и в примере для процедурных типов (см. шаг 32).
unit Unit2; { Прообраз стандартной библиотеки пользователя } interface type TMyFunc = function ( X : Integer ) : Real of object; TMyClass1 = class private FField : Real; FMyFunc: TMyFunc; protected function FirstFunc ( X : Integer ) : Real; procedure SetField ( Value : Real ); public procedure TakeAndSet ( X : Integer ); property Field : Real read FField write SetField; property MyFunc : TMyFunc read FMyFunc write FMyFunc; end; var MyObject1 : TMyClass1; implementation function TMyClass1.FirstFunc ( X : Integer ) : Real; begin Result := SQR ( X )/2; end; procedure TMyClass1.SetField ( Value : Real ); begin FField := Value end; procedure TMyClass1.TakeAndSet ( X : Integer ); begin SetField (MyFunc(X)); end; initialization MyObject1 := TMyClass1.Create; MyObject1.MyFunc := MyObject1.FirstFunc; finalization MyObject1.Free; end.
unit Unit1; { Приложение, использующее стандартный модуль Unit2 } { и выполняющее делегирование "своего" метода SecondFunc } { импортируемому из Unit2 объекту MyObject1 } interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Unit2; type TForm1 = class(TForm) Edit1: TEdit; Edit2: TEdit; Label1: TLabel; Label2: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; TMyClass2 = class function SecondFunc ( X : Integer ) : Real; end; var Form1: TForm1; MyObject2 : TMyClass2; implementation {$R *.dfm} function TMyClass2.SecondFunc ( X : Integer ) : Real; begin Result := SQRT ( X )*2; end; procedure TForm1.FormCreate(Sender: TObject); var St: String; begin with MyObject1 do begin TakeAndSet(16); {Устанавливает значение 128} Str (Field:7:2, St); Edit1.Text := St; MyObject2:= TMyClass2.Create; MyFunc:= MyObject2.SecondFunc; { Делегирование } TakeAndSet(16); { Устанавливает значение 8} Str (Field:7:2, St); Edit2.Text:= St; MyObject2.Free; end; end; end.
Результат:
Рис.1. Результат работы приложения
В этом примере описаны два модуля: Unit2 содержит прообраз библиотеки пользователя, a Unit1 - прообраз приложения, использующего эту библиотеку. В модуле Unit2 объявлен класс TMyClass1, содержащий свойство MyFunc процедурного типа, и объект этого класса MyObject1, который в инициализационной части модуля стандартным образом настраивается на использование своего внутреннего метода FirstFunc. В результате метод TakeAndSet класса TMyClass1, который делает вызов метода, присвоенного свойству MyFunc, по умолчанию будет вызывать FirstFunc. Однако благодаря процедурному типу свойства MyFunc в приложении, использующем библиотеку, метод TakeAndSet можно перенастроить так, что он будет вызывать метод SecondFunc из класса TMyClass2, который совместим по типу с методом FirstFunc. Такая передача действия, описанного в одном классе, методу из другого класса называется делегированием. В данном примере делегирование выполняется оператором:
MyFunc := MyVar2.SecondFunc;
Поскольку события Delphi реализованы в виде процедурных свойств, которые можно изменять во время работы программы, то для них также применимо делегирование. Чтобы делегировать свой метод стандартному событию Delphi, нужно знать вид заголовка метода, который обрабатывает это событие. Например, тип TNotifyEvent описан для событий, которые не имеют дополнительных параметров.
type TNotifyEvent = procedure(Sender: TObject) of object;
Описанный в типе единственный параметр Sender является стандартным параметром всех обработчиков событий.
На следующем шаге мы рассмотрим классовые методы.