![]() |
Re: Auf Interfaces zugreifen?
Zitat:
Prkatisch sind sie zum Beispiel bei der XML API, wenn man nach Belieben eine Library durch eine andere ersetzen kann, da die API einheitlich ist. Wenn ein Anbieter nette Extrafeatures hat, oder die Library besonders schlank ist, muss man nicht erst drei Tage lang refaktorisieren :) Und mit Interfaces kann man das gut von der Festlegung auf vorgegebene Klassenhierarchien trennen. Java macht das schon seit Ewigkeiten (JDBC, Mail-API, Servlet-API JMS, ...), und die Hersteller der dazu passenden Implementierungen freuen sich, dass sie eine stabile Vorgabe haben - Design by Contract sozusagen - die den berüchtigten Vendor-Lock-In verhindert. Doch bei Delphi gibt es natürlich auch Teile, die ähnlich arbeiten, dbExpress zum Beispiel, keine Frage. Wenn Delphi ein Problem mit Interfaces hat, dann eher weil der Anwender sich vertun kann bei der Mischung von Objekt- und Interfacereferenzen, oder wenn TComponent eigene Besitzerverwaltung praktiziert (und man das nicht bedenkt). Fazit: ich liebe Interfaces. Viele Grüße, Michael |
Re: Auf Interfaces zugreifen?
Zitat:
Zitat:
|
Re: Auf Interfaces zugreifen?
Hallo,
bin wieder bei den Interfaces angekommen. Hab jetzt diesen Ansatz:
Delphi-Quellcode:
unit UAppIntfFactory;
interface uses Classes, Sysutils, Contnrs, UAppIntf; var Interfaces: TInterfaceList; //In DElphi eingebaut ClassesIntf: TObjectList; //In DElphi eingebaut Interfaced: IAppInterface; procedure SetClassOf(Instance: TObject); procedure SetInterfaceOf(Name: String); function GetInterfaceOf(Name: String): IInterface; function GetClassOf(Instance: TObject): TObject; implementation uses UAppIntfImpl; procedure SetClassOf(Instance: TObject); begin if Assigned(ClassesIntf) then begin ClassesIntf.Add(Instance); end; end; procedure SetInterfaceOf(Name: String); begin if Assigned(Interfaces) then begin Interfaces.Add(Interfaced); end; end; function GetClassOf(Instance: TObject): TObject; var Index: Integer; begin if Assigned(ClassesIntf) then begin Index := 0; while Index < ClassesIntf.Count do begin { if Instance is Classesintf.Items[index] then begin Result := ClassesIntf.Items[Index]; Index := ClassesIntf.Count; end; } Inc(Index); end; end; end; function GetInterfaceOf(Name: String): IInterface; var Index: Integer; begin if Assigned(Interfaces) then begin Result := Interfaces.Items[Index]; end; end; initialization Interfaces := TInterfaceList.Create; ClassesIntf := TObjectList.Create; finalization ClassesIntf.Free; Interfaces.Free; end. //Hier die Implementation der Klassen: unit UAppIntfImpl; interface uses Classes, Sysutils, Dialogs, UAppIntf, UAppIntfFactory; type TAppIntfImpl = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; TAppIntfImpl2 = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; var InterfacedClass1: TAppIntfImpl; InterfacedClass2: TAppIntfImpl2; implementation { TAppIntfImpl } procedure TAppIntfImpl.DoSomething; begin ShowMessage('the Interfaced method von TAppIntfImpl'); end; procedure TAppIntfImpl2.DoSomething; begin ShowMessage('the Interfaced method von TAppIntfImpl2'); end; initialization //InterfacedClass := TAppIntfImpl.Create; if Assigned(Interfaces) then begin Interfaces.Add( InterfacedClass1 ); Interfaces.Add( InterfacedClass2 ); end; if Assigned(ClassesIntf) then begin ClassesIntf.Add(InterfacedClass1); ClassesIntf.Add(InterfacedClass2); end; //InterfacedClass.Free; end. //Hier kommt die Anwendung: unit UAppIntfUser; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, UAppIntf, StdCtrls, UAppIntfFactory, UAppIntfImpl; type TForm1 = class(TForm) Button1: TButton; cbxIntfChange: TComboBox; lbIntfChange: TLabel; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure cbxIntfChangeCloseUp(Sender: TObject); private { Private-Deklarationen } FInterfaceExists: Boolean; public FInterface: IAppInterface; { Public-Deklarationen } FInterfaced: IAppInterface; FInterface2: TAppIntfImpl; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin if FInterfaceExists then //FInterfaced.DoSomething; FInterface2.DoSomething; end; procedure TForm1.cbxIntfChangeCloseUp(Sender: TObject); var Index: Integer; begin Index := cbxIntfChange.ItemIndex; cbxIntfChange.Text := cbxIntfChange.Items.Strings[Index]; //FInterfaced := Interfaces.Items[Index]; //------ Hier kommt eine Listen-Index-Exception, die ich mir nicht erklären kann FInterface2 := TAppIntfImpl(ClassesIntf.Items[index]); end; procedure TForm1.FormCreate(Sender: TObject); begin FInterfaceExists := true; //FInterfaced := GetInterfaceOf('Impl2'); end; end. |
Re: Auf Interfaces zugreifen?
Falls du das bis jetzt überlesen hast: NIEMALS! Objektvariablen und Interfacevariablen für ein und das selbe Objekt.
Wenn deine Faktory die Objekte erzeugen soll, die IAppInterface unterstützen, dann gehören die Units die diese Objekte deklarieren, nirgends sonst eingebunden. Die konkrete Implementation geht niemanden etwas an, maximal die Faktory kennt diese, um die Objekte zu erzeugen. Die Faktory liefert IAppInterface, also sind alle Variablen außerhalb auch IAppInterface. Hier mal eine Skizze wie eine Faktory funktionieren könnte:
Delphi-Quellcode:
Classname ist natürlich keine schöne Unterscheidung der Klassen, aber dafür kann man in TCustomAppInterface ja ein eigenes class Property / class Methode vorsehen.
unit UAppIntfDef;
type TCustomAppInterface = class(TInterfacedObject, IAppInterface) constructor Create; virtual; // virtualer Constructor für die Faktory procedure DoSomething; virtual; abstract; end; TAppInterfaceClass = class of TCustomAppInterface; implementation {********************} unit UAppIntfFactory; uses UAppIntfDef; function RegisterAppInterface(AClass: TAppInterfaceClass); procedure GetAppInterfaces(AItems: TStrings); function GetAppInterface(AName: string): IAppInterface; implementation var FClasses: TClassList; function RegisterAppInterface(AClass: TAppInterfaceClass); begin FClasses.Add(AClass); end; procedure GetAppInterfaces(AItems: TStrings); begin AItems.Clear; for i := 0 to FClasses.Count - 1 do begin AItems.Add(FClasses[i].ClassName; end; end; function GetAppInterface(AName: string): IAppInterface; begin for i := 0 to FClasses.Count - 1 do begin if FClasses[i].ClassName = AName then begin Result := TAppInterfaceClass(FClasses[i]).Create; Exit; end; end; end; {********************} unit UAppIntfImpl1; interface implementation uses UAppIntfDef, UAppIntfFactory; type TAppIntfImpl = class(TInterfacedObject, IAppInterface) procedure DoSomething; end; procedure TAppIntfImpl.DoSomething; begin end; begin RegisterAppInterface(TAppIntfImpl); end. {********************} unit UAppIntfImpl2; interface implementation uses UAppIntfDef, UAppIntfFactory; type TAppIntfImp2 = class(TInterfacedObject, IAppInterface) constructor Create; override; procedure DoSomething; end; constructor TAppIntfImp2.Create; begin end; procedure TAppIntfImp2.DoSomething; begin end; begin RegisterAppInterface(TAppIntfImp2); end. {********************} unit UAppIntfUser; type TForm1 = class(TForm) private FInterface: IAppInterface; end; procedure TForm1.FormCreate(Sender: TObject); begin FInterface := GetAppInterface('TAppIntfImp1'); end; procedure TForm1.RadioButtonClick(Sender: TObject); var s: string; begin if Sender = RadioButton1 then s := 'TAppIntfImp1' else if Sender = RadioButton2 then s := 'TAppIntfImp2' else Exit; FInterface := GetAppInterface(s); end; procedure TForm1.ButtonClick(Sender: TObject); begin FInterface.DoSomething; end; |
Re: Auf Interfaces zugreifen?
Hallo,
die Funktion GetAppInterface sollte auch dann ein definiertes Ergebnis liefern, wenn man ihr einen unbekannten Klassennamen übergibt. Alternativ könnte sie natürlich eine Exception auslösen. Gruß Hawkeye |
Re: Auf Interfaces zugreifen?
GetAppInterface gibt hier nil zurück, wenn ein unbekannter Klassenname angegeben wird.
Im Prinzip hast du mit der Exception recht, aber das ist wie gesagt nur eine Skizze. |
Re: Auf Interfaces zugreifen?
Hallo Blup,
Zitat:
Delphi-Quellcode:
Die
function F1: IInterface;
begin Result := TInterfacedObject.Create; end; function F2: IInterface; begin end; procedure P1; var I: IInterface; begin I := F1(); if Assigned(I) then ShowMessage ('nach F1(): I <> nil'); I := F2(); if Assigned(I) then ShowMessage ('nach F2(): I <> nil'); end; ![]() Gruß Hawkeye |
Re: Auf Interfaces zugreifen?
Gut zu wissen, schlecht das der Compiler für diesen Fall keine Warnmeldung gibt.
Delphi-Quellcode:
function GetAppInterface(AName: string): IAppInterface;
begin for i := 0 to FClasses.Count - 1 do begin if FClasses[i].ClassName = AName then begin Result := TAppInterfaceClass(FClasses[i]).Create; Exit; end; end; Result := nil; end; |
Re: Auf Interfaces zugreifen?
@Hawkeye219: Das selbe Verhalten gibt es übrigens auch bei Strings und dynamischen Arrays.
[edit] ich seh grad, in der verlinkten Seite geht es um die Strings (dachte es geht da um das Interface), aber ist ja bei allem das Selbe. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:53 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz