Oldalak

2012. augusztus 1., szerda

Flyweight minta alkalmazása

A Flyweight (pehelysúlyú) szerkezeti objektum minta megvalósítása Delphi alatt. Ezt a mintát valósítja meg a TCollection és TCollectionItem osztály. Ezt a gyakorlatban olyan esetekben szoktam használni, amikor dinamikusan összetett adatokat kell kezelni és a hagyományos tömb szerkezet ehhez nem nyújt kellő rugalmasságot.

A TCollection és TCollectionItem osztályokból származtatott saját konténer osztályok alkalmazásával ki lehet aknázni az OOP által nyújtott előnyöket mint például a kollekcióba szervezett adatok belső integritásának védelme, vagy az adatok állapot változásának esemény kezelése saját eseménykezelők használatával (pl. ha a kollekcióban egy elem állapota megváltozik, akkor egy eseménykezelőben kezelni lehessen a bekövetkezett változásokat).

A Flyweight minta megvalósítása örökléssel a TCollection és TCollectionItem osztályokból (ez csak egy kód csontváz, amit igazából az adott célnak megfelelően kell elkészíteni, kiegészíteni a feladathoz leginkább illeszkedő mezőkkel, metódusokkal) Kollekció elem csontváz osztály interface része:
interface

uses
  Classes, ...;

type
  TMyCustomDataItem = class(TCollectionItem)
  private
    // itt kell definiálni azokat a mezők tároló változóit,
    // amit majd a külvilág felé publikálni szeretnénk tulajdonságokon
    // keresztül
    FMyIntField    : Integer;
    FMyStringField : String;
    ...
  public
    constructor Create(Collection: TCollection); override;
    ...
    property MyIntField : Integer read FMyIntField write FMyIntField;
    property MyStringField : String read FMyStringField write FMyStringField;
    ...
  end;
A kollekció elem publikált mezőihez lehet getter/setter metódusokat definiálni, ezt a konkrét feladat dönti el, hogy mire van szükségünk. Ha például eseményt szeretnénk kiváltani, ha egy elemnek (TCollectionItem) megváltozik a belső állapota, akkor a figyelni kívánt tulajdonság setter metódusát kell "felokosítani" erre a feladatra, hogy az állapot változásról értesítse ki a kollekciót kezelő objektumot (TCollection). Kollekció csontváz osztály interface része:
  ...
  TMyCustomDataCollection = class(TCollection)
  private
    function GetMyCustomDataItem(Index : Integer) : TMyCustomDataItem;
    procedure SetMyCustomDataItem(Index : Integer; 
      const Value : TMyCustomDataItem);
  public
    destructor Destroy; override;

    function Add : TMyCustomDataItem; overload;
    function Add(AMyInt : Integer; AMyString : String) : TMyCustomDataItem; overload;

    procedure DeleteAll;
    procedure OrderByMyIntField;
    property Items[Index : Integer] : TMyCustomDataItem read GetMyCustomDataItem
      write SetMyCustomDataItem;
  end;
A fenti példában a TMyCustomDataCollection osztályt felruházom rendezés funkcióval, ami a MyIntField mező szerint fogja a kollekcióban az elemeket sorba rendezni, az összes elem törlése funkció, egyedi adatokkal történő a adat inicializálás Add(1, 'MyString'). TMyCustomDataItem osztály implementációs csontváza:
...
implementation
{ TMyCustomDataItem }

constructor TMyCustomDataItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FMyIntField := $F0F0;
  FMyStringField := '';
  ..
  // további inicializáló utasítások
end;
TMyCustomDataCollection kollekció implementációs csontváza:
{ TMyCustomDataCollection }

destructor TMyCustomDataCollection.Destroy;
begin
  DeleteAll;
  inherited Destroy;
end;

function TMyCustomDataCollection.Add: TMyCustomDataItem;
begin
  Result := inherited Add as TMyCustomDataItem;
end;

function TMyCustomDataCollection.Add(AMyInt : Integer; AMyString : String): TMyCustomDataItem;
begin
  Result := inherited Add as TMyCustomDataItem;
  Result.MyIntField := AMyInt;
  Result.MyStringField := AMyString;
  ..
  // további értékadó utasítások
end;

procedure TMyCustomDataCollection.DeleteAll;
begin
  while (Self.Count > 0) do
    Self.Delete(0);
end;

function TMyCustomDataCollection.GetMyCustomDataItem(Index: Integer): TMyCustomDataItem;
begin
  Result := inherited Items[Index] as TMyCustomDataItem;
end;

procedure TMyCustomDataCollection.SetMyCustomDataItem(Index: Integer;
  const Value: TMyCustomDataItem);
begin
  inherited Items[Index] := Value;
end;

procedure TMyCustomDataCollection.OrderBySessionNum;
var
  iIndex        : Integer;
  iIndex2       : Integer;
  pMinItem      : TMyCustomDataItem;
  pCurrItem     : TMyCustomDataItem;
begin
  // elemek rendezése FMyInt szám szerint növekvő sorrendben
  // a min sort algoritmusnál van gyorsabb rendezés is ;)
  for iIndex := 0 to Self.Count - 1 do
    begin
      pMinItem := Self.Items[iIndex];

      for iIndex2 := iIndex to Self.Count - 1 do
        begin
          pCurrItem := Self.Items[iIndex2];
          if pCurrItem.SessionNum < pMinItem.SessionNum then
            begin
              pCurrItem.Index := pMinItem.Index;
              pMinItem := pCurrItem;
            end;
        end;
    end;
end;
A fenti csontvázak alapján a saját igényeknek megfelelően kell tovább bővíteni a kollekció és kollekció elem osztályokat.

Nincsenek megjegyzések:

Megjegyzés küldése