Bonjour,

Aprés les différentes discussion à propos des interfaces, une question est apparue dans ma petite tête. Et si un objet pouvait supporter des interfaces de façon dynamique et servir ainsi de concentrateur de tous les délégués?...hum interessant...non?

Voici comment j'ai implémenté ça:
une optimisation possible serait de créer une liste clé/valeur pour remplacer la liste d'interfaces.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
 
unit IntfUnt;
 
interface
 
uses Classes, SysUtils;
 
type
  ISupportDynamique = interface
    ['{0770742D-FAB0-4027-A31E-D704F4142BF3}']
    procedure EnregistrerObjet(const IID: TGUID; const ImplObj: IInterface);
    procedure SupprimerTousLesObjets;
  end;
 
function NouveauSupportDynamique: ISupportDynamique;
 
implementation
 
type
  TSupportDynamique = class(TInterfacedObject, IInterface, ISupportDynamique)
  private
    FIntfs: IInterfaceList; //liste clé/valeur (string -> obj) serait mieux ici
  protected
    function  QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    procedure EnregistrerObjet(const IID: TGUID; const ImplObj: IInterface);
    procedure SupprimerTousLesObjets;
  public
    constructor Create;
  end;
 
  IInfoObjet = interface
    ['{1EAFA560-8D8D-4743-B960-C0694DA23D28}']
    function ObjetImplementeur: IInterface;
  end;
 
  TInfoObjet = class(TInterfacedObject, IInfoObjet)
  private
    FObjet: IInterface;
  private
    function ObjetImplementeur: IInterface;
  public
    constructor Create(const ObjetImplementeur: IInterface);
  end;
 
function NouveauSupportDynamique: ISupportDynamique;
begin
  Result := TSupportDynamique.Create;
end;
 
{ TSupportDynamique }
 
constructor TSupportDynamique.Create;
begin
  inherited Create;
  FIntfs := TInterfaceList.Create;
end;
 
procedure TSupportDynamique.EnregistrerObjet(const IID: TGUID;
  const ImplObj: IInterface);
var
  info: IInfoObjet;
begin
  info := TInfoObjet.Create(ImplObj);
  FIntfs.Add(info);
end;
 
function TSupportDynamique.QueryInterface(const IID: TGUID; out Obj): HResult;
var
  temp: IInterface;
  info: IInfoObjet;
  i: integer;
begin
  Result := E_NOINTERFACE;
 
  if GetInterface(IID, Obj) then
  begin
    Result := S_OK;
    Exit;
  end;
 
  //ici idéalement une liste GUID -> Obj plutôt que IInterfaceList
  FIntfs.Lock;
  try
    for i := 0 to FIntfs.Count - 1 do
    begin
      info := FIntfs.Items[i] as IInfoObjet;
 
      if not Assigned(info) then
        Exit;
 
      temp := info.ObjetImplementeur;
 
      if Supports(temp, IID, Obj) then
      begin
        Result := S_OK;
        Exit;
      end;
    end;
  finally
    FIntfs.Unlock;
  end;
end;
 
procedure TSupportDynamique.SupprimerTousLesObjets;
begin
  FIntfs.Clear;
end;
 
{ TInfoObjet }
 
constructor TInfoObjet.Create(const ObjetImplementeur: IInterface);
begin
  inherited Create;
  FObjet := ObjetImplementeur;
end;
 
function TInfoObjet.ObjetImplementeur: IInterface;
begin
  Result := FObjet;
end;
 
end.

utilisation:

j'ai crée 2 unités simple definissant 2 interfaces ISalut et IBonjour

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
unit BonjourIntf;
 
interface
 
uses Dialogs;
 
type
  IBonjour = interface
    ['{B1B342C7-28D0-4CED-BAC3-748D87153F48}']
    procedure Bonjour;
  end;
 
function NouveauBonjour: IBonjour;
 
implementation
 
type
  TBonjour = class(TInterfacedObject, IBonjour)
    procedure Bonjour;
  end;
 
function NouveauBonjour: IBonjour;
begin
  Result := TBonjour.Create;
end;
 
{ TBonjour }
 
procedure TBonjour.Bonjour;
begin
  ShowMessage('Bonjour');
end;
 
end.
et ISalut

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
unit SalutIntf;
 
interface
 
uses Dialogs;
 
type
  ISalut = interface
    ['{CA2EB942-4DEA-4315-9E51-7954182D2661}']
    procedure Salut;
  end;
 
function NouveauSalut: ISalut;
 
implementation
 
type
  TSalut = class(TInterfacedObject, ISalut)
    procedure Salut;
  end;
 
function NouveauSalut: ISalut;
begin
  Result := TSalut.Create;
end;
 
{ TSalut }
 
procedure TSalut.Salut;
begin
  ShowMessage('Salut');
end;
 
end.

dans ma fiche principale, je crée un ISupportDynamique et je lui enregistre un ISalut et IBonjour

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
 
    FDynaObj: ISupportDynamique;
 
(...)
 
 
procedure TForm5.FormCreate(Sender: TObject);
begin
  FDynaObj := NouveauSupportDynamique;
 
  FDynaObj.EnregistrerObjet(ISalut, NouveauSalut);
  FDynaObj.EnregistrerObjet(IBonjour, NouveauBonjour);
end;

maintenant que les objets sont enregistrer, je peut accéder au service ISalut et IBonjour comme ceci.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
 
  (FDynaObj as ISalut).Salut;
  (FDynaObj as IBonjour).Bonjour;

FDynaObj implémente maintenant ISalut et IBonjour par délégation


Commentaires, critiques, améliorations, pièce de 5 centimes......sont acceptés