вторник, 8 февраля 2011 г.

Введение в обобщенное программирование (Generics) - 4 (События,методы класса)

Обобщения в событиях
Как вы знаете, события в Delphi очень похожи на процедурные типы, но в отличие от них они могут быть определены только в объектах. Так как внутренний механизм событий и процедруных типов идентичен – то вы можете использовать обобщения и в событиях. В отличие от процедурных типов, в событиях компилятор требует наличие дополнительного параметра, который является объектом, передающимся в данную процедуру.
В этом примере мы создадим обобщенное определение события (Procedure Of Object), которое будет уведомлять нас о любых изменениях:
unit ProcedureOfObject;

interface

type
 // Обобщенное событие
 TMyNotifyChange = Procedure(Value: T) Of Object;

 TStorage= Class
                table: array of T_Value;
                NotifyValueChanged  : TMyNotifyChange;
                NotifyStorageChanged: TMyNotifyChange>;
                constructor Create(size: Integer);
                procedure AddValue(index: Integer; Value: T_Value);
               end;

implementation

// -- Type TStorage
constructor TStorage.Create(size: Integer);
begin
  Inherited Create;
  SetLength(table, size);
end;

procedure TStorage.AddValue(index: Integer; Value: T_Value);
begin
  table[index] := Value;
  // Вызываем обработчики
  if Assigned(NotifyValueChanged) then
    NotifyValueChanged(Value);
  if Assigned(NotifyStorageChanged) then
    NotifyStorageChanged(Self);
end;

begin
end.
После чего, мы можем использовать такие события в головной программе:
GenericProcedureOfObject
program GenericProcedureOfObject;

uses
  SysUtils,
  ProcedureOfObject in 'ProcedureOfObject.pas';

Type
  TStatistics = Class
    Storage: TStorage;
    constructor CreateStatistics;
    procedure DisplayValueChanged(value: Integer);
    procedure DisplayStorageChanged(storage: TStorage);
  end;

constructor TStatistics.CreateStatistics;
begin
  Inherited Create;
  Storage := TStorage.Create(5);
  // Определяем обработчики событий
  Storage.NotifyValueChanged   := DisplayValueChanged;
  Storage.NotifyStorageChanged := DisplayStorageChanged;
end;

procedure TStatistics.DisplayValueChanged(value: Integer);
begin
  Writeln('added_value -> ', value);
end;

procedure TStatistics.DisplayStorageChanged(storage : TStorage);
var
  index: Integer;
begin
  Writeln('added_value to ');
  for index := 0 to Length(storage.table) - 1 do
      Writeln('  ', storage.table[index]);
end;

var
  Statistics : TStatistics;
begin
  Statistics := TStatistics.CreateStatistics;
  Statistics.Storage.AddValue(0, 33);
  Writeln;
  write('type enter');
  Readln;
end.

Обобщения в методах
Также мы можем использовать обобщения в методах класса:
unit Method;

interface

type
  TProduct = class
    price: Double;
    quantity: Integer;
    Constructor Create(Price: Double; Quantity: Integer);
    procedure Display(Text: String; Value: T);
  end;

implementation

Constructor TProduct.Create(Price: Double; Quantity: Integer);
begin
  Inherited Create;
  price := Price;
  quantity := Quantity;
end;

procedure TProduct.Display(Text: String; Value: T);
begin
  // в Delphi.NET раскоментируйте следующую строку
  // writeln(Text, Value.ToString);
end;

end.
Использовать обобщенный метод можно так:
procedure UseGenericMethod;
var
  product: TProduct;
begin
  product := TProduct.Create(218.15, 34);
  product.display('the price is    ', product.price);
  product.display('the quantity is ', product.quantity);
end;
Мы можем создать обобщенный метод класса с помощью конструкции языка Class procedure. Такие методы класса можно вызывать непосредственно, без необходимости создания объекта:
unit ClassMethod;

interface

type
  TSort = Class
    Class procedure Swap(Var one, two: T); Static;
  end; // TSort

implementation

Class procedure TSort.Swap(Var one, two: T);
var
  Temporary: T;
begin
  Temporary := two;
  two := one;
  one := Temporary
end;

begin
end.
Пример показывающий использование такого метода представлен ниже:
procedure UseGenericClassMethod;
var
  Sort : TSort;
  entier1, entier2: Integer;
  double1, double2: Double;
begin
  entier1 := 10;
  entier2 := 200;
  writeln('original ', entier1:5, entier2:5);
  sort.swap(entier2, entier1);
  writeln('    swap ', entier1:5, entier2:5);
  writeln;
  double1 := 1.11;
  double2 := 333.33;
  writeln('original ', double1:7:2, ' ', double2:7:2);
  sort.swap(double1, double2);
  writeln('    swap ', double1:7:2, ' ', double2:7:2);
end;

Продолжение следует…



Комментариев нет:

Отправить комментарий