Poids-mouche

Le poids-mouche (flyweight) est un patron de conception structurel. C’est à dire qu’il défini comment organiser les classes d’un programme dans une structure plus large. L’interface est séparée de l’implémentation.

Quand l’utiliser ?

Ce patron de conception poids-mouche est à utiliser quand de nombreux et petits objets doivent être manipulés mais qu’il serait trop coûteux en mémoire de tous les instancier. Le patron est chargé de les instancier à la demande de l’utilisateur.

Exemple

Pou mettre en place ce patron,  prenons une fabrique d’insecte (poids-mouche oblige :-)).

Tout d’abord création, commençons par la création d’une interface IInsecte et d’une classe TInsecte.

type
  IInsecte = interface
    procedure Operation;
  end;
 
  TInsecte = class(TInterfacedObject, IInsecte)
    procedure Operation; virtual; abstract;
  end;
 
  TInsecteClass = class of TInsecte;

La classe TInsecteClass sera utilisée un peut plus loin dans cette démonstration.

Continuions avec la création de quelques insectes :

  TMoustique = class(TInsecte)
    procedure Operation; override;
  end;
 
  TFourmi = class(TInsecte)
    procedure Operation; override;
  end;
 
  TAbeille = class(TInsecte)
    procedure Operation; override;
  end;
 
  TPapillon = class(TInsecte)
    procedure Operation; override;
  end;
 
implementation
 
{ TMoustique }
 
procedure TMoustique.Operation;
begin
  Writeln('>> un moustique');
end;
 
{ TFourmi }
 
procedure TFourmi.Operation;
begin
  Writeln('>> une fourmi');
end;
 
{ TAbeille }
 
procedure TAbeille.Operation;
begin
  Writeln('>> une abeille');
end;
 
{ TPapillon }
 
procedure TPapillon.Operation;
begin
  Writeln('>> un papillon');
end;

Passons pour finir à la création du patron, le TFabriqueInsecte. Un dictionnaire est utilisé pour stocker le tuple clé-classe (d’ou l’intérêt du TInsecteClass).

Une TObjectList d’insectes permet de stocker les objets créés par le patron.

  TFabriqueInsecte = class
  private
    FListClass: TDictionary<string, TInsecteClass>;
    FList: TObjectList;
  public
    constructor Create;
    destructor Destroy; override;
 
    function GetInsecte(aKey: string): TInsecte;
  end;

Ensuite lors de la création du patron, le dictionnaire est alimenté avec les différents types, aucun insecte n’est pour l’instant créé, seul la définition est enregistrée.

{ TFabriqueInsecte }
 
constructor TFabriqueInsecte.Create;
begin
  inherited Create;
 
  FListClass := TDictionary<string, TInsecteClass>.Create;
 
  FListClass.Add('moustique', TMoustique);
  FListClass.Add('fourmi', TFourmi);
  FListClass.Add('abeille', TAbeille);
 
  FList := TObjectList.Create;
end;
 
destructor TFabriqueInsecte.Destroy;
begin
  FList.Free;
 
  inherited Destroy;
end;

Puis la fonction GetInsecte est chargée de créer et stocker à la demande l’insecte qui correspond à la clé.

function TFabriqueInsecte.GetInsecte(aKey: string): TInsecte;
var
  InsecteClass: TInsecteClass;
begin
  if FListClass.TryGetValue(aKey, InsecteClass) then
  begin
    FList.Add(InsecteClass.Create);
    Result := FList[FList.Count - 1];
  end
  else
  begin
    Result := nil;
  end;
end;

Pour finir, voici un exemple d’utilisation du patron ci-dessus :

var
  Fabrique: TFabriqueInsecte;
  Insecte: TInsecte;
begin
  try
    Fabrique := TFabriqueInsecte.Create;
    try
      Insecte := Fabrique.GetInsecte('moustique');
      Insecte.Operation;
 
      Insecte := Fabrique.GetInsecte('fourmi');
      Insecte.Operation;
 
      Insecte := Fabrique.GetInsecte('abeille');
      Insecte.Operation;
 
      // un insecte créé directement depuis la classe
      Insecte := TPapillon.Create;
      try
        Insecte.Operation;
      finally
        Insecte.Free;
      end;
    finally
      Fabrique.Free;
    end;
 
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*