Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Schon wieder: Warum Interfaces (https://www.delphipraxis.net/190600-schon-wieder-warum-interfaces.html)

exilant 19. Okt 2016 21:31

Schon wieder: Warum Interfaces
 
Ich muss mich mal outen: Seit vielen Jahren entwickle und pflege ich mit Delphi eine ziemlich umfangreiche Branchenanwendung (In House, neuerdings mehrere Standorte). Nach Ausflügen zu C# und PHP/Javascript bin ich doch immer wieder bei Delphi gelandet. Jetzt steht die Modernisierung vieler älterer Module an und ich beschäftige mich seit Tagen intensiv mit Interfaces. Bisher ein weißer Fleck auf meiner Delphi Landkarte.

Ja: Auch im Jahre 2016 AD gibt es es immer noch Entwickler die mit „plain old delphi objects“ coden.
Nun gehe ich mal davon aus, dass all‘ die Delphi-Gurus hier und anderswo nicht aus rein modischen Gründen und nicht erst seit gestern die Verwendung von Interfaces immer und überall bevorzugen sondern gute Gründe dafür haben.

Ich habe dazu mehrfach den Abschnitt in Nick Hodges Buch (Coding in Delphi) zu dem Thema gelesen. Ein großes Plädoyer für die Programmierung mit Interfaces. Weiterhin habe ich gegoogled was das Zeug hält und auch viele Beiträge hier im Forum durchgeackert. Ich habe mir selbst mal ein paar Interfaces gebastelt und damit gespielt. Lange Rede, kurzer Sinn: Ich glaube prinzipiell verstanden zu haben wie Interfaces funktionieren auch wenn ich einige hiesige Forumsbeiträge zum Thema keineswegs verstanden habe.
Bei vielen verstehe mitunter nicht mal über welches Problem geschrieben wird. Offensichtlich sind es jedoch manches Mal Probleme die man ohne Interfaces nicht hätte. Das „reference counting“ finde ich z. B. nach meinem derzeitigen Verständnis von interfaces gelinde gesagt sche.. ääh nicht gut.

Wie dem auch sei: Der Knackpunkt bei der Frage nach dem Einsatz von Interfaces ist für mich das „Warum“. Darauf habe ich nirgendwo eine befriedigende Antwort bekommen. Ich zitiere mal (ich hoffe, das ist OK) eine Passage aus dem Text von Nick Hodges, (Buch „Coding in Delphi“, Blog) aus dem Abschnitt
„Why Do You Want To Use Interfaces?“ um mein Problem zu verdeutlichen:

Zitat:

Nick Hodges, Blog Coding in Delphi
[...]Say you have a large system with different teams working on different major modules.* Those teams are responsible for providing functionality in their own modules, and thus they are responsible for the integrity and quality of the code in their modules.* Let’s say you are on the Widget team, and you need the Sprocket team to do something for you.* You go to the Sprocket guys and say “Hey, I need to add a few things in the Sprocket code so that we can do some Sprocket-type stuff in our Widget.”* The Sprocket guys are going to laugh at you – like they are going to let you poke around in their carefully crafted system!* No, instead, they will likely ask you want you need, build the functionality, and hand you some code with an interface and a factory for creating an implementation of that interface.* They aren’t going to let you anywhere near their code – but they are happy to let you have an interface into that code.* You get what you want – some Sprocket functionality – and they don’t have to expose anything more than an interface to you.* And later, if they completely re-architect their code, what do you care?* Your interface still works, even if they completely change the internal implementation.* That’s a sound way to develop, all made possible because of interfaces....
Das folgende Staement irritiert mich außerordentlich:
Zitat:

..Your interface still works, even if they completely change the internal implementation.* That’s a sound way to develop, all made possible because of interfaces.
Nochmal: „...all made possible because of interfaces.“????? Das gilt so auch für Klassen. Warum soll das oben beschriebene Widget/Sprocket Problem durch Interfaces erst lösbar sein? Ich hantiere (wie viele andere) alltäglich mit Klassen, über deren Implementierung ich nichts weiß, nichts wissen will und auch nichts wissen muss. Das ist doch ein wesentliches Merkmal von klassischer OOP.

Aber dann natürlich

Zitat:

If you choose not to embrace interfaces, then you are locking yourself out of new and effective programming frameworks and techniques.* Or, put another way, all the cool kids are doing interfaces, and you want to be part of the cool kid group, right?
Ja. ich will zu den coolen Kids gehören. Ich ahne, dass da was ist was ich nicht sehe. Und damit komme ich zum Schluss und zu einer konkreten Bitte: Kann mir irgendwer hier ein Beispiel, entsprechende Links oder Literaturempfehlungen posten denen ein durchaus erfahrener, aber mit Interfaces nicht vertrauter Entwickler entnehmen kann worin der Nutzen von Interfaces gegenüber einer „normalen“ Hierarchie aus (auch abstrakten) Klassen liegt. Was kann ich damit exklusiv tun? Und wenn nicht exklusiv, dann zumindest einfacher oder besser. Vermutlich sind all‘ die Beispiele die ich bisher gelesen habe zu trivial. Zu komplexe waren allerdings auch dabei. Ich erkenne einfach den Nutzen von Interfaces immer noch nicht. Lasst mich nicht dumm sterben!

stahli 19. Okt 2016 23:14

AW: Schon wieder: Warum Interfaces
 
Nettes Thema :-)

Ich hatte mal etwas dazu zusammen gestellt: http://www.delphipraxis.net/183702-i...-factorys.html

Also ich würde mal 3 Punkte aufzählen:
+ Entkopplung
+ Austauschbarkeit
+- Referenzzählung


Entkopplung:

Wenn Du ein TAuto konstruierst, musst Du ein TMotor, TLenkrad und TRad benutzen und diese irgendwo verbinden.
Dazu musst Du bei der Verwendung von Klassen die kompletten Units kennen und einbinden.
Wenn der Motor jetzt z.B. wissen müsste, in was für einem Auto er steckt und ob das Auto gerade auf einem Prüfstand fährt ;-), dann muss TMotor u.U. TAuto kennen.
So hat man schnell überkreuzende Referenzen und muss sehen, dass man diese Probleme irgendwie löst.
Auch hat man indirekt ziemlich viel Ballast (in Form von Klassenmembers), den man später gar nicht braucht.

Wenn Du mit Interfaces arbeitest, kannst Du das leichter abstrahieren.
Kurz gesagt, man arbeitet nur noch mit dem Wesentlichen.

Es interessiert dann nicht mehr, wo und wie die Klasse deklariert ist. Ich habe etwas mit festgelegten Eigenschaften und Methoden und kann das benutzen ohne mich mit der ganzen Klasse befassen oder diese kennen zu müssen.


Austauschbarkeit:

Es gibt ein Auto, einen Motor, Lenkrad und Räder. Was das genau für Räder sind, Luftbereift, Vollgummi oder was auch immer spielt keine Rolle.

Wenn so ein Rad eine bestimmte Aufnahme auch wieder als Schnittstelle beinhaltet kannst Du später die Räder durch andere Klassen ersetzen (z.B. AntiGravitationsräder) wenn diese die gleiche Schnittstelle für die Räderbefestigung haben.

Auf "klassischem" Wege müsstest Du die neuen Räder von TRad ableiten, um dieses in der Autoklasse verwenden zu können. Wenn aber das neue Rad auch von TNeuesMaterial abgeleitet werden müsste, damit eine Werkstatt das herstellen kann, hat man ein Problem.

Mit Verwendung von Interfaces kann das neue Rad mehrere Erfordernisse unterstützen

TNewWheel = class(TInterfacedObject, IWheel, INewMaterial)

Jetzt kann die Werkstatt mit dem Objekt umgehen, da es NewMaterial ist und das Auto kann damit fahren, weil es ein Rad ist.

Man kann auch leicht DummyObjekte bauen, die erst einmal bestimmte Funktionen simulieren.
Wenn Du das mit echten Klassen machen willst, musst Du direkt in Dein Projekt eingreifen und das später wieder korrigieren.

Wenn Du mit Interfaces arbeitest, kannst Du leichter von außen ein DummyObjekt in Dein Projekt herein reichen, das so tut, als wäre es ein echtes Businessobjekt, aber intern einfach erst mal bestimmte Funktionen simuliert (und auch von einer völlig anderen Basisklasse abgeleitet ist).


Referenzzählung:

Das ist Fluch und Segen, aber auch optional.

InterfacedObjects in Delphi zählen mit, wie oft sie benutzt werden. Fällt die letzte Nutzung weg (indem einer Variablen z.B. Nil zugewiesen wird oder das Programm den Scope verlässt, in dem die Variable erzeugt wurde, dann wird das Objekt freigegeben.
Man muss bzw. darf daher für Interface-Variablen nie Free aufrufen. Statt dessen darf man Nil zuweisen, was aber beim Verlassen eines Scopes auch automatisch erfolgt.
Also man muss Interface-Variablen nicht freigeben, wenn man es will, dann nur durch Nil-Zuweisung.

Eigentlich ist das eine ganz nette Sache, aber es hat zwei Haken:
Wen ich in aMotor ein Motor-Interface habe und ich Nil zuweise (aMotor := Nil) kann es sein, dass das Objekt noch nicht freigegeben wird, weil irgendwo im Speicher möglicherweise noch ein Zugriff auf dieses Interface existiert (z.B. in einer Liste oder so).
Durch meine Nil-Zuweisung wird der RefCounter verringert (z.B. von 2 auf 1) und das Objekt aber erst bei 0 freigegeben.

Für die Liste existiert der Motor noch.
Wenn man mit Objekten arbeitet und hier aMotor.Free angegeben hätte, könnte es später bei Zugriff auf die Motoren-Objekte in der Liste knallen.

Bei Motoren-Interfaces in der Liste knallt nix, da das Objekt noch nicht freigegeben wurde.

Wenn ich aber vorhin das Objekt wirklich FREIGEBEN wollte, dann kann das Projekt den Motor noch verwenden, der eigentlich aber nicht mehr existieren sollte.

Ok, welche fehlerhafte Arbeit des Projektes ist die schlechtere? Das kann man so nicht entscheiden. Wichtig ist, dass man bei Vewrwendung von Interfaces mit Referenzzählung beachten muss, dass man nicht ohne weiteres in der Hand hat, wann das Objekt tatsächlich freigegeben wird.


Noch komplizierter wird es bei gegenseitigen Referenzen.
Man stelle sich vor, das Moterinterface würde das Interface der Liste kennen, in der es steht.
Jetzt entfällt von außen der letzte Zugriff auf die Liste und der RefCounter wird reduziert und läuft auf 0.
Die Liste wird automatisch freigegeben...

...wäre schön, aber klappt nicht, da das MotorInterfaceobjekt in der Liste ja eine Referenz auf die Liste hält.
Der RefCounter der Liste kann also durch Maßnahmen von außen nur auf 1 fallen. Also wird die Liste nie aufgelöst.
Auch das MotorInterfecedObjekt wird nie aufgelöst, da es ja von der Liste referenziert wird.

In solchen Fällen muss man dann selbst für das Aufräumen sorgen.
Man könnte für die Liste Clear aufrufen, wodurch die Referenzen auf die Items entfallen und auch die Referenz des Motors auf die Liste entfällt und alles freigegeben wird.

Dies braucht aber eine explizite Veranlassung.

Dennoch ist die Referenzzählung eine ganz angenehme Handhabung. Man muss aber berücksichtigen, dass es insgesamt ein anderes Handling ist.

Man kann allerdings auch Interface-Objekte ohne Referenzzählung verwenden.
Dann bestimmt man die Lebenszeit der Objekte weiterhin selbst, kann aber Objekte weiterhin leichter austauschen.
Das währe dann ähnlich einem Cast zu sehen.

Wenn man klassisch verschiedenste Objekte einer Methode übergeben will
Delphi-Quellcode:
uses
  ...alle Units, die ein fahrbares Objekt deklarieren...

procedure Fahre(O: TObject)
begin
  if (O is TAuto) then
    (O as TAuto).Fahre;
  if (O is TFahrrad) then
    (O as TFahrrad).Fahre;
end;
müsste man in der Methode das Objekt in TFahrrad oder TAuto casten.

Mit Interfaces könnte man folgendes deklarieren:
Delphi-Quellcode:
uses
  MyInterfaces;

procedure Fahre(FahrbaresObjekt: IKannFahren)
begin
  FahrbaresObjekt.Fahre;
end;

Aviator 19. Okt 2016 23:44

AW: Schon wieder: Warum Interfaces
 
Also mich interessiert die Frage ja auch brennend. Ich habe noch nie wirklich einen überzeugenden Grund gefunden, der was "Wieso" beschreibt.

Ich würde unheimlich gerne mit Interfaces arbeiten und habe auch schon das eine oder andere Mal meine Klassen mit einem Interface aufgebaut. Aber oft sehe ich einfach nicht die Notwendigkeit. Ich arbeite nie im Team sondern immer alleine. Somit muss ich mit niemandem meinen Code teilen.

Aktuell habe ich ein Projekt, bei dem ich eine Schnittstelle nach außen bringen muss. Hierzu programmiere ich mehrere DLLs. Dort bieten sich Interfaces natürlich extrem gut an. Und dort verstehe ich auch das "Wieso".

Meine DLL muss nur noch eine Methode exportieren. Und zwar eine (ich nenne sie immer so) GetInstance Methode, welche mir eine Instanz zu einem Interface liefert. Der Vorteil ist der, dass ich das Interface nur einmal definieren muss und kann es jedem zur Verfügung stellen. Somit entfällt diese ganze Schreiberei für denjenigen, der die DLL benutzen will. Auf der anderen Seite würde derjenige der die DLL nutzt, nur die Methoden in sein Programm aufnehmen, welche er wirklich auf verwenden will.

Das Interface bei der DLL hat eben noch den Vorteil (im Vergleich zu normal exportierten Methoden), dass dahinter eine Klasse stehen kann, welche direkt angesprochen wird. Mit Objekten ist das ja so eine Sache. Das funktioniert da ja dann nicht so einfach. Und die Klasse im Bezug auf Interfaces hat eben den Vorteil, dass da instanzspezifisch Daten gespeichert werden können welche dann auch nur über spezielle Interfacemethoden wieder abgerufen werden können.


Nur wenn ich eine Klasse schreibe die genau eine Aufgabe hat und ich weiß, dass da niemals mehr etwas hinzu kommt, dann erschließt sich mir der Sinn eines Interfaces einfach nicht.

Klar, die Referenzzählung ist eine schöne Sache. Man muss einfach nicht mehr auf das Object.Free achten. Aber das ist so drin bei mir, dass ich das eigentlich nie vergesse. Und wenn doch, dann schreit ReportMemoryLeaksOnShutdown nach Hilfe. :-D

@Stahli: Nichts für Ungut, aber ich sehe mich was Interfaces angeht auf einem leicht höheren Level als den TE. Und ich finde deine Beispiele doch recht schwierig zu verstehen. Ich hatte damals den Thread von dir (den du ja auch wieder verlinkt hast) aufmerksam verfolgt. Eben weil mich das Thema Interfaces so interessiert und ich mich weiterbilden will. Durch das Thema bin ich damals zwar durchgestiegen, aber es wurde auch nie wirklich ein "Wieso" Grund genannt, welcher mich überzeugt hätte.

Das soll jetzt auf keinen Fall böse wirken oder so. :shock:


Sir Rufo ist doch unser Interface Spezialist hier. Er macht doch für alles und jeden ein Interface. Vielleicht hat er ja einen alles übertreffenden Grund parat. Leider hat er schon länger nichts mehr hier geschrieben. :cyclops:

Ich hoffe meine Antwort (obwohl ich nahezu so unwissend bin wie der TE) hat dem TE und/oder anderen Lesern die vor dem gleichen Problem stehen trotzdem ein wenig geholfen. :roll:

Luckie 19. Okt 2016 23:58

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von Aviator (Beitrag 1351412)
Sir Rufo ist doch unser Interface Spezialist hier.

Sir Rufo IST ein Interface. :mrgreen:

Mavarik 20. Okt 2016 00:21

AW: Schon wieder: Warum Interfaces
 
Also DLL geht bei mir so:

Delphi-Quellcode:
Procedure SetInterface(Var DLL:IGoogleMapsDLL);
begin
  DLL := TGoogleMaps.Create;
end;

Exports
  SetInterface;
So compiliere ich eine Unit mit dem TMS-Google Maps Komponenten in eine DLL, die ich dann problemlos von D2007 aus nutzen kann.

Und das Fenster wird in der DLL erzeugt:

Delphi-Quellcode:
function MapInit(ParentWnd: hwnd; R: TRect): hWnd; : hwnd;
begin
  FGoogleMapForm := TGoogleMapForm.CreateParented(ParentWnd);
  FGoogleMapForm.Layout.Height := R.Height;
  FGoogleMapForm.Layout.Width := R.Width;
  FGoogleMapForm.Layout.Realign;
  FGoogleMapForm.Init;(Mini,Internet,DIP91,MapStreetLevel);
  SetWindowPos(FGoogleMapForm.Layout.Handle,0,R.Left,R.Top,R.Right-R.Left,R.Bottom-R.Top,0);
  Result := FGoogleMapForm.Layout.Handle; //Frame.Handle;
end;
Fertig... So brauche ich in D2007 weder einen Link zu den TMS Units, noch muss ich wissen was die machen... Auch keine Komponenten installieren.

uvm...

Zum Beispiel linke ich so eine PDF DLL bei der ich die Units nur im XE6/DCU Format habe gegen jede Delphi Version...

Hierzu mache ich/wir "die Tage" noch einen Workshop...

DeddyH 20. Okt 2016 06:45

AW: Schon wieder: Warum Interfaces
 
Und das hat genau was mit Interfaces zu tun?

[edit] Um noch etwas Konstruktives beizutragen:
- Bei der Verwendung von Interfaces muss keine bestimmte Klassenhierarchie eingehalten werden, da der Verwender lediglich das Interface sieht und nicht die dahinterstehende Klasse.
- Interfaces können modulübergreifend (Anwendung <-> DLL) verwendet werden, im Gegensatz zu Objekten (OK, das ginge mit BPLs, die sind aber versionsabhängig).
- Eine Klasse kann beliebig viele Interfaces implementieren, damit erreicht man so etwas ähnliches wie Mehrfachvererbung.
- Bei Verzicht auf sprachspezifische Typen und/oder Konstrukte können Interfaces sprachunabhängig verwendet werden.

Mehr fällt mir spontan nicht ein, vielleicht meldet sich Stevie ja noch ;) [/edit]

Jasocul 20. Okt 2016 07:20

AW: Schon wieder: Warum Interfaces
 
Ein Spezialist für Interfaces bin ich sicher nicht und ich nutze die auch nur rudimentär. Aber vielleicht bin ich deshalb der Richtige für das "wieso". :)
Ich stand auch mal vor dieser Frage und bin auf dieses Beispiel gestoßen.
Natürlich kann man das auch mit einer Basisklasse lösen, die entsprechende abstrakte Methoden verwendet, aber denkt man wirklich von Anfang an, an alle möglichen Dinge?
Es ist sicher möglich, die Basisklasse später zu ergänzen, ist in dem Fall aber gezwungen, auch alle Nachkommen anzupassen. Mit einem Interface kann man das auch einfach in den Nachkommen bei Bedarf machen.

Verwendet habe ich das zum Beispiel bei einer TreeView. Dort wurden viele Objekte eingebunden. Um die Darstellung zu vereinfachen, bekam jedes Objekt ein Interface mit Methoden, die mir eine vernünftige Bezeichnung liefern und bei Bedarf verschiedene Berechnungen machten. Durch das Interface waren alle Bezeichner einheitlich, egal, welches Objekt dahinter stand.
Auch das Problem kann man sicher klassisch mit OOP lösen, aber ich fand die Lösung mit dem Interface schon ziemlich praktisch.

Ghostwalker 20. Okt 2016 07:33

AW: Schon wieder: Warum Interfaces
 
Hi,

da ich mich auch grad mit Interfaces beschäftige ist das natürlich auch für mich interresant.

Ein (wie ich meine) gute Beschreibung findest du im "Delphi Developer's Handbook" von Marco Cantú.


Die Vorteile die ich darin sehe, sind folgende:

- Übersichtlichkeit

Selbst wenn man nur alleine Entwickelt, sammeln sich im laufe der Zeit einiges an Klassen
an. Wenn ich die später nutzen möchte, interressiert mich nicht, wie ich das implementiert
hab, sonder welche Methoden/Propertys ich habe und Was gemacht wird.

- Sprachunabhängigkeit

Du kannst Klassen auch in anderen Sprachen (C,C++,C# oder what ever) schreiben und in Delphi
nutzen.

- COM/COM+/DCOM

Die Nutzung dieser Windows-Techniken ist schlicht und ergreifend ohne Interfaces nicht möglich,
da das ganze System drauf beruht (z.B. Einbindung von Word, Excel usw.). Auch die Nutzung
von ActiveX-Komponenten wird dadurch erst möglich.

Fazit (für mich soweit):

Es gibt etliche Situationen, in denen Interfaces sinnvoll einzusetzen sind. Deshalb aber zwanghaft
überall Inferfaces einzusetzen wäre aber übertrieben.

DeddyH 20. Okt 2016 07:46

AW: Schon wieder: Warum Interfaces
 
Noch ein Vorteil: man kann seine Klassen quasi in einer Art Baukastenprinzip designen. Eine Klasse soll etwas bestimmtes können: entsprechendes Interface implementieren. Sie soll auch etwas anderes können: weiteres entsprechendes Interface implementieren. Auf Verwenderseite kann man dann einfach abfragen, ob ein Interface implementiert ist und dies dann nutzen.

bra 20. Okt 2016 08:56

AW: Schon wieder: Warum Interfaces
 
Der einzige Grund, wieso ich bisher bewusst ein Interface eingesetzt habe (von COM und sowas mal abgesehen), war, dass ich Mehrfachvererbung für eine Klasse brauchte. Ist mir bis heute unverständlich, wieso Delphi sowas nicht unterstützt.

Lemmy 20. Okt 2016 09:03

AW: Schon wieder: Warum Interfaces
 
Ich finde, Interface-Programmierung verhält sich zu OOP wie die OOP zur prozeduralen Programmierung.

Grundsätzlich kannst Du jedes Problem auch ohne Interfaces und ohne OOP lösen. Und keinen interessiert es. Allerdings handelst Du dir immer irgend welche Probleme ein, in der Fachwelt wird dafür der Begriff der technischen Schulden verwendet. Keiner sieht sie, man riecht sie nicht und eines Tages schwappen sie über dich :-)

Genauso wenig wie

Delphi-Quellcode:
type
  TFoo = class(TObject)
  public
    procedure DoFoo; //mit 1.000 Zeile Code
  end;
objektorientierte Programmierung ist, ist die Definition eines Interfaces, die Implementierung und Verwendung davon automatisch auch eine sinnvolle Verwendung eines Interfaces, weil es oft schlicht und ergreifend nur mehr Arbeit ist aber keinen Vorteil bietet, weil man die Technik falsch anwendet bzw. im falschen Kontext.

Interfaces sind eine logische Weiterführung der OOP, vielleicht müsste man auch sagen, eine zwingende Weiterführung. Aber es ist wie gesagt nicht damit getan ein

Delphi-Quellcode:
type
  IFoo = Interface
    procedure DoFoo;
  end;
zu schreiben und zu Jubeln "Ich kann Interfaces", sondern dann folgen automatisch auch weiter Punkte die dann wichtig werden, denn Interfaces werfen wie vieles andere auch, mehr Fragen auf, als sie beantworten :-) Als ein Stichpunkt werfe ich hier nur mal Dependency Injection ein.


Der große Vorteil von Interfaces eröffnet sich erst in etwas komplexeren Systemen, in denen div. Klassen miteinander kommunizieren müssen. Hier hast Du die Möglichkeit, dass diese Klassen weiterhin miteinander arbeiten könne, sich aber gegenseitig nicht mehr persönlich kennen müssen:

Delphi-Quellcode:
TAdresse = class()
...
public
  function GetAnrede: String;
  function GetName1: String;
  function GetName2: String;
  function GetStrasse: String;
....
end;

TPerson = class()
private
  FName, FVOrname: String;
  FStrasse: String;
....
public
  property Adresse: TAdresse read FAdresse;
Und damit wir einen Konsumenten haben:

Delphi-Quellcode:
TBrief = class()
public
  procedure ErstelleBrief(Empfaenger: TAdresse);
end;
hier hast Du einen harte Kopplung wie sie in div. Projekten vorkommt und alles ist OK.
Willst Du jetzt aber TBrief durch einen Unittest jagen hast Du das Problem, dass Du zwingend auch eine Instanz von TAdresse erzeugen und übergeben musst. Kein Problem, solange TAdresse keine weiteren Abhängigkeiten hat. Sobald das System und das BOM komplexer werden, wirst Du hier immer mehr abhängige Klassen vorbereiten müssen, instanziieren müssen bis du zu dem Punkt kommst: Unittests sind scheiße, weil Du für eine Zeile Testcode, 10, 20 Zeilen Code für die Instanziierung und für die Aufräumaktionen brauchst. Und du merkst nicht, dass eigentlich dein Modell ein Problem hat.

Mit Interfaces sieht das ganze so aus:

Delphi-Quellcode:
IAdresse = Interface
  function GetAnrede: String;
  function GetName1: String;
  function GetName2: String;
  function GetStrasse: String;
end;

TPerson = class()
private
  FName, FVOrname: String;
  FStrasse: String;
....
public
  property Adresse: IAdresse read FAdresse;
Und damit wir einen Konsumenten haben:

Delphi-Quellcode:
TBrief = class()
public
  procedure ErstelleBrief(Empfaenger: IAdresse);
end;
Nun kann TPerson selbst entscheiden, welche Implementierung von IAdresse (es kann mehrere geben) für seinen Zwecke am besten ist. TBrief ist das aber völlig egal, durch das Interface weiß die Klasse, dass die vertraglich vereinbarten Methoden vorhanden sind und funktionieren, d.h. Du kannst TBrief dann auch damit verwenden:

Delphi-Quellcode:
type
  TStudent = class(X,IAdresse)
  ...
  public
    function GetAnrede: String;
    function GetName1: String;
    function GetName2: String;
    function GetStrasse: String;
und TStudent muss kein weiteres Element deines TPerson-Frameworks kennen, muss nicht von einer gemeinsamen Basisklasse abgeleitet werden,....


Kommen wir aber nochmal zurück zur TPerson: ich habe oben geschrieben, dass TPerson entscheidet welche Implementierung von IAdresse es verwendet. Das ist aber schon wieder ein Fehler! Weil du baust dir hier wieder über die Hintertür eine harte Kopplung von 2 Klassen ein. Und genau das kann später wieder zu einem Problem werden, weil du dann an dem Punkt bis: Verflixt, jetzt wollte ich harte Kopplung vermeinden, muss aber halt irgend wo implementieren:

Delphi-Quellcode:
TPerson = class()
private
  FName, FVOrname: String;
  FStrasse: String;
....
public
  property Adresse: IAdresse read FAdresse;

...

TPerson.Create()
begin
  FAdresse := TFooAdresse.Create();
end;
Lösung für dieses Problem bietet die Dependency Injection: Ich kopple das Interface nicht an einer bestimmten Stelle mit einer konkreten Implementierung sondern biete über eine Liste (sog. Container) verschiedene Möglichkeiten an (oder vielleicht auch nur eine) wie IAdresse implementiert sein soll. TPerson instanziiert dann die IAdresse nicht selbst, sondern fragt bei der Liste an: Gib mir eine Instanz von IAdresse. Aber den Part könnte Stefan G. nun wirklich besser erklären :-)

wie auch bei der OOP ist auch bei Interfaces das Problem: Mit 2 Sätzen und einem einfachen Beispiel ist das nicht erklärt....

OlafSt 20. Okt 2016 09:54

AW: Schon wieder: Warum Interfaces
 
All das ist ja alles sehr interessant und auch absolut sinnvoll. Nebenbei, ich gehöre auch zu denen, die gern was mit Interfaces machen würden (und auch schon mögliche Projekte in der Pipeline haben), aber irgendwie über eine Brücke nicht rüberkommen.

Meine Blockade ist die vielbeschworene Sprachenunabhängigkeit. Man schreibt eine DLL in Delphi, schraubt ein paar Interfaces um die Klassen herum und kann das dann in C# verwenden. Wie soll das aussehen, kann da jemand einen 30-Zeiler (okay, weils 2 Sprachen sind, 60-Zeiler) zusammenschustern, wo man das mal sehen kann ?

stahli 20. Okt 2016 10:03

AW: Schon wieder: Warum Interfaces
 
@DeddyH + vor allem Lemmy

:thumb:
So etwa hätte ich das auch sagen wollen... :oops:


@OlafSt

Dazu hat Mavarik ja etwas angekündigt. Ich selbst habe diesbezüglich keine Erfahrungen.

Mavarik 20. Okt 2016 10:33

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von exilant (Beitrag 1351410)
Das „reference counting“ finde ich z. B. nach meinem derzeitigen Verständnis von interfaces gelinde gesagt sche.. ääh nicht gut.

Genau das war mein Grund sich näher mit Interfaces zu beschäftigen... Thema Arc unter Windows... Um eine FMX App gleicht unter Mobil und Windows zu programmieren, nimmt man keine Objecte, sondern Interfaces, so mit gibt es keinen Plattformunterschied.


Zitat:

Zitat von DeddyH (Beitrag 1351421)
Und das hat genau was mit Interfaces zu tun?

Frage an mich? Hast nix gequotete... Nur so kann ich etwas verwenden ohne einen Link zu Klasse...


Zitat:

Zitat von stahli (Beitrag 1351411)

Referenzzählung:
...

Eigentlich ist das eine ganz nette Sache, aber es hat zwei Haken:
Wen ich in aMotor ein Motor-Interface habe und ich Nil zuweise (aMotor := Nil) kann es sein, dass das Objekt noch nicht freigegeben wird, weil irgendwo im Speicher möglicherweise noch ein Zugriff auf dieses Interface existiert (z.B. in einer Liste oder so).
Durch meine Nil-Zuweisung wird der RefCounter verringert (z.B. von 2 auf 1) und das Objekt aber erst bei 0 freigegeben.

Für die Liste existiert der Motor noch.
Wenn man mit Objekten arbeitet und hier aMotor.Free angegeben hätte, könnte es später bei Zugriff auf die Motoren-Objekte in der Liste knallen.

Bei Motoren-Interfaces in der Liste knallt nix, da das Objekt noch nicht freigegeben wurde.

Wenn ich aber vorhin das Objekt wirklich FREIGEBEN wollte, dann kann das Projekt den Motor noch verwenden, der eigentlich aber nicht mehr existieren sollte.

Ok, welche fehlerhafte Arbeit des Projektes ist die schlechtere? Das kann man so nicht entscheiden. Wichtig ist, dass man bei Vewrwendung von Interfaces mit Referenzzählung beachten muss, dass man nicht ohne weiteres in der Hand hat, wann das Objekt tatsächlich freigegeben wird.

Na zum Glück gibt es für Interfaces "jetzt" das Attribut [WEAK] somit bewirkt Dein Whatever := NIL, wenn Du alle anderen Referenzen mit [WEAK] geflaged hast wirklich ein Free...

Wenn ich etwas in einer Liste speichere, und das "Ding" an andererstelle Frei geben, dann wollte ich es - wenn es in der Liste ist - sicherlich noch verwenden, oder?

Ich brauche einfach nicht die Try Finally ketten...

Delphi-Quellcode:
begin
  AFoo := TFoo.Create;
  try
    ABar := TBar.Create;
    try
      AFile := TFilestream.Create(..)
      try
        ABar.LoadFormStream(AFile);
        AFoo.Add(ABar);
        AFoo.Machwas;
      finally
        AFile.Free;
      end;
    finally
      ABar.free; // ggf. könnte ich das AFoo überlassen, aber dann würde ich im Source immer darüber stolpern.
    end;
  finally
   AFoo.Free;
  end;
end;
oder

Delphi-Quellcode:
begin
  IFoo := TFoo.Construct(TBar.Construct(TiFile.Construct(..)));
  IFoo.Machwas;
end;
Mavarik :coder:

Jim Carrey 20. Okt 2016 10:35

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von OlafSt (Beitrag 1351454)
All das ist ja alles sehr interessant und auch absolut sinnvoll. Nebenbei, ich gehöre auch zu denen, die gern was mit Interfaces machen würden (und auch schon mögliche Projekte in der Pipeline haben), aber irgendwie über eine Brücke nicht rüberkommen.

Meine Blockade ist die vielbeschworene Sprachenunabhängigkeit. Man schreibt eine DLL in Delphi, schraubt ein paar Interfaces um die Klassen herum und kann das dann in C# verwenden. Wie soll das aussehen, kann da jemand einen 30-Zeiler (okay, weils 2 Sprachen sind, 60-Zeiler) zusammenschustern, wo man das mal sehen kann ?

Ich verstehe Interfaces auch in keinster Art und Weise.
Ich bin der Meinung... solange man der alleinige Entwickler an einem Projekt ist, ist es vollkommen egal was man verwendet.
Hauptsache man versteht seinen eigenen Code, er funktioniert und lässt sich gut ändern.

Gegenfrage: haben Interfaces irgendeinen Vorteil in der erzeugten Programmdatei?

Mavarik 20. Okt 2016 10:39

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von Jim Carrey (Beitrag 1351460)
Gegenfrage: haben Interfaces irgendeinen Vorteil in der erzeugten Programmdatei?

Klar...

Aber 90% der Vorteile sind für Dich als Entwickler...

Ein Beispiel:

Code:
SchreibeDatenWeg.exe /SQLite
SchreibeDatenWeg.exe /REST:https://www.meinserver.de
SchreibeDatenWeg.exe /MySQL
ist in der exe 1. Zeile

Delphi-Quellcode:
IDatenZiel := TDatenWriter.CreateFromParamOrDefault(Params);

Jim Carrey 20. Okt 2016 10:41

AW: Schon wieder: Warum Interfaces
 
Also kann man grundlegend festhalten, dass Interfaces immens zur Code-Minimierung beitragen wenn nicht sogar dafür vorgesehen sind?

Mavarik 20. Okt 2016 10:46

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von stahli (Beitrag 1351455)

@OlafSt

Dazu hat Mavarik ja etwas angekündigt. Ich selbst habe diesbezüglich keine Erfahrungen.


Höchstwahrscheinlich - ab Januar, wenn ich meine Youtube-Tutorial Reihe zu meinem FDK beginne.

Das FDK arbeiten hauptsächlich - aus den genannten Gründen (Windows & ARC) - mit Interfaces.

Aviator 20. Okt 2016 10:50

AW: Schon wieder: Warum Interfaces
 
Ich sehe aktuell wie bereits geschrieben den Vorteil in Interfaces, wenn man DLLs programmieren will um seinen Code irgendwie auszulagern. Dann haben die Dinger extreme Vorteile.

Ein anderer Punkt an dem man Interfaces verwenden kann ist eben dann, wenn man 2 unterschiedliche Klassen hat, die aber die gleichen Informationen zur Anzeige auf der GUI zur Verfügung stellen sollen. Jede Klasse verarbeitet die Informationen allerdings anders und daher ist auch das angezeigte Ergebnis ein anderes. Die Abfrage im Programm bleibt aber immer gleich.

Delphi-Quellcode:
ITest = interface
  function GetValue: string;
end;

Delphi-Quellcode:
TMyClass1 = class(TInterfacedObject, ITest)
  function GetValue: string;
end;

implementation

function TMyClass1.GetValue: string;
begin
  Result := 'Das ist der Wert aus MyClass1';
end;
Delphi-Quellcode:
TMyClass2 = class(TInterfacedObject, ITest)
  function GetValue: string;
end;

implementation

function TMyClass2.GetValue: string;
begin
  Result := 'Das ist der Wert aus MyClass2';
end;
Delphi-Quellcode:
TForm1 = class(TForm)
  procedure ShowValue(FromInterface: ITest);
end;

implementation

function TForm1.ShowValue(FromInterface: ITest);
begin
  Label1.Caption := FromInterface.GetValue;
end;
Hier habe ich jetzt den Vorteil, dass ich einfach eine beliebige Interface Instanz übergeben bekomme aus der ich mir dann mit dem gleichen Aufruf die benötigten Informationen ziehen kann. Das würde bei Klassen zwar auch gehen, aber dafür müssten alle übergebenen Klassen von der gleichen Basisklasse abgeleitet werden. Diese müsste wiederum eine abstrakte Methode GetValue zur Verfügung stellen, welche von jeder Ableitung implementiert werden muss. In diesem Fall sind Interfaces deutlich leichter zu handlen.

Wenn man allerdings nur eine Klasse hat welche Informationen zur Verfügung stellen soll, dann lohnt sich ein Interface meines Erachtens nicht wirklich. Man hat nur den Vorteil den Mavarik angesprochen hat. Diese try..finally Blöcke und das Object.Free fallen weg. Wenn man die Interface Instanzen dann korrekt verwendet, dann sollte man auch kein Problem mit der Referenzzählung haben.

Mavarik 20. Okt 2016 11:07

AW: Schon wieder: Warum Interfaces
 
Was mir noch einfällt.

Beispiel mit : IStreamPersist

Delphi-Quellcode:
TFoo = Class(TInterfacedObject,ICanCompress);
...
TBar = Class(TInterfacedObject,ICanCompress,IStreamPersist)
Jetzt kann ich abfragen, ob ein Object, dass Interface unterstützt. Und dann in einen Stream schreiben oder vom Stream lesen...

Jim Carrey 20. Okt 2016 11:36

AW: Schon wieder: Warum Interfaces
 
Kompliziert kompliziert :oops:

Ich finde dann doch den ausführlichen alten Code besser.

stahli 20. Okt 2016 11:54

AW: Schon wieder: Warum Interfaces
 
@Aviator

Das ist gut zusammengefasst.

Interfaces sind halt nur in bestimmten Konstellationen sinnvoll.
Wenn Du ein paar Klasen in einem übersichtlichen Projekt nutzt, ist der Mehraufwand von Interfaces meist nicht zu rechtfertigen.

Wenn Du aber sehr viele Klassen in einem komplexen System nutzt und möglicherweise mehrere Klassen gleiche Funktionalitäten unterstützen müssen, dann helfen Interfaces sehr stark.

Auch die Übersichtlichkeit über die Projektbestandteile wird verbessert wenn man alle genutzten Interfaces in einer Unit vor sich hat und deren Beziehungen direkter nachvollziehen kann als wenn man konkrete Klassen in unterschiedlichen Units nachschlagen muss.

Auch sehr hilfreich finde ich, dass die Units, die die Klassen deklarieren, nur an einer zentralen Stelle bekannt sein müssen.
Die Unit1 muss nicht Unit2 kennen und umgekehrt. Beide - und auch die anderen Projektbestandteile - müssen nur MyInterfaces und MyFactory kennen und haben damit Zugang zu allem Benötigten.


@Jim

So kompliziert ist das gar nicht - ich hab´s ja auch verstanden. :-)

Das ist wie vor ein paar Jahren, als alle sich fragten, was das mit den Objekten eigentlich soll... ;-)

Irgendwann findet man schon etwas, wo dann Interfaces plötzlich sinnvoll erscheinen.

Jim Carrey 20. Okt 2016 12:02

AW: Schon wieder: Warum Interfaces
 
Zitat:

So kompliziert ist das gar nicht - ich hab´s ja auch verstanden.
Das klingt total bawertend :D

Zitat:

Irgendwann findet man schon etwas, wo dann Interfaces plötzlich sinnvoll erscheinen.
Dafür muss man sie aber erst verstehen :P

DeddyH 20. Okt 2016 12:05

AW: Schon wieder: Warum Interfaces
 
Ich hab mich auch 20 Jahre davor gedrückt, als ich mich aber vor Kurzem damit beschäftigt habe, war das eigentlich simpel zu verstehen.

Aviator 20. Okt 2016 12:26

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von Jim Carrey (Beitrag 1351479)
Zitat:

So kompliziert ist das gar nicht - ich hab´s ja auch verstanden.
Das klingt total bawertend :D

Er hat es ja auf sich selbst bezogen. Wenn er es versteht, dann verstehen es auch alle anderen. :stupid: :spin2:
Immerhin hat er Humor. :thumb:

Zitat:

Zitat von stahli (Beitrag 1351477)
@Aviator

Das ist gut zusammengefasst.

Danke! :thumb:

Interfaces sind wie schon beschrieben sowohl positiv als auch negativ. Das Prinzip wie sie funktionieren habe ich mittlerweile doch recht gut verstanden. Und das ist immer das Wichtigste (bei allem im Leben). Man muss das Prinzip verstehen.

Nur manchmal sehe ich eben keine Notwendigkeit dafür oder weiß nicht, das an einer bestimmten Stelle ein Interface von Vorteil wäre. Da tue ich mich aktuell noch ein bisschen schwer damit.


Zur Delphi IDE kann ich sagen, dass mich lediglich das Verfolgen einer durch ein Interface implementierten Methode etwas stört. STRG + Linksklick auf den Aufruf einer Interface-Methode führt immer nur zum Interface selbst. Wenn man sich mal Visual Studio anschaut, dann führt es einen immer direkt zu der Klasse, welche oben auch instanziiert wurde. (Ich hoffe ich verwechsele das nicht)

Das würde ich mir bei Delphi auch wünschen. Aber ich will jetzt keine Diskussion starten, welche IDE in dem Fall besser wäre. Ist nur meine persönliche Meinung.

stahli 20. Okt 2016 12:57

AW: Schon wieder: Warum Interfaces
 
Die Darstellung der Interfaces in den überwachten Ausdrücken kann man sich etwas optimieren: http://www.delphipraxis.net/189852-u...ptimieren.html

Es ist leider etwas aufwendig, aber zumindest geht es.

Aviator 20. Okt 2016 12:59

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von stahli (Beitrag 1351489)
Die Darstellung der Interfaces in den überwachten Ausdrücken kann man sich etwas optimieren: http://www.delphipraxis.net/189852-u...ptimieren.html

Es ist leider etwas aufwendig, aber zumindest geht es.

Ja das Thema hatte ich damals mitverfolgt. Nur habe ich mich damit nicht mehr weiter auseinander gesetzt. Muss man dann für jedes Interface einen eigenen Visualizer bauen? Das wäre ja extrem aufwendig. :shock:

Jumpy 20. Okt 2016 13:04

AW: Schon wieder: Warum Interfaces
 
Ich meine einer hat es schon erwähnt, aber beim 2. durchlesen des Threads hab ich es nicht mehr gefunden:
Gerade wenn man viel mit Unittests usw. arbeitet macht die Verwendung von Interfaces die Klassen leichter testbar, da so eine entkopplung von konkreten Implementierungen stattfindet. Und da Entkopplung eines der hohen Ziele der OOP bzw. auch des CleanCodes ist, wird das halt vielfach so gepredigt. Wie schon Lemmy sagte. Es reicht nicht nur Interfaces zu verwenden und alles ist gut. Man muss sie auch richtig verwenden, im richtigen Zusammenhang.

DeddyH 20. Okt 2016 13:10

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von Jumpy (Beitrag 1351496)
Man muss sie auch richtig verwenden, im richtigen Zusammenhang.

Und auch nur dann, wenn die erhöhte Abstraktion Sinn macht, und nicht, um irgendwie hipp zu wirken.

Aviator 20. Okt 2016 13:32

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von DeddyH (Beitrag 1351498)
Zitat:

Zitat von Jumpy (Beitrag 1351496)
Man muss sie auch richtig verwenden, im richtigen Zusammenhang.

Und auch nur dann, wenn die erhöhte Abstraktion Sinn macht, und nicht, um irgendwie hipp zu wirken.

Stimme ich voll und ganz zu. Und genau dafür konnte ich noch keine "Regel" finden. Wann benutzt man sie nicht weil es hipp ist, sondern weil es Sinn macht?!

DeddyH 20. Okt 2016 13:37

AW: Schon wieder: Warum Interfaces
 
Eine goldene Regel dafür kenne ich auch nicht, aber je dynamischer (besonders im Hinblick auf die Klassentruktur) und/oder offener (im Hinblick auf externe Schnittstellen) ein Projekt wird, desto sinnvoller wird der Gebrauch von Interfaces IMO.

stahli 20. Okt 2016 13:57

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von Aviator (Beitrag 1351493)
Zitat:

Zitat von stahli (Beitrag 1351489)
Die Darstellung der Interfaces in den überwachten Ausdrücken kann man sich etwas optimieren: http://www.delphipraxis.net/189852-u...ptimieren.html

Es ist leider etwas aufwendig, aber zumindest geht es.

Ja das Thema hatte ich damals mitverfolgt. Nur habe ich mich damit nicht mehr weiter auseinander gesetzt. Muss man dann für jedes Interface einen eigenen Visualizer bauen? Das wäre ja extrem aufwendig. :shock:

Ja, wobei Vererbungen bei der Darstellung berücksichtigt werden können.
Wenn man also eine Darstellung für IMyInt hat, kann diese auch für IMyIntA und IMyIntB genutzt werden.
Wobei man Ableitungen von Interfaces eher vermeiden sollte. Hier werden ja eher Funktionalitäten beschrieben und dabei ist es i.d.R. sinnvoll, viele kleine eigenständige Funktionalitäten (Interfaces) zu definieren als von anderen abzuleiten.

Wenn man IMyInt1 und IMyInt2 und möchte jetzt ein IMyInt3, das die beiden anderen implementiert, könnte man ja nur von einem ableiten und müsste den anderen Bereich wieder nachbilden.

Besser wäre es somit, in IMyInt3 nur die Neuerungen zu definieren und einer späteren Klasse alle drei Interfaces zuzuweisen:

TMyClass = class(TInterfacedObject, IMyInt1, IMyInt2, IMyInt3)

Also, da Vererbungen von Interfaces die Ausnahme sein werden, wäre für jedes Interface eine eigene Visualisierung zu regeln.
Das kann man aber in Form von Bedingungsprüfungen in einer Unit regeln:
if (TypeName = 'IMyInt1') then
...
if (TypeName = 'IMyInt2') then
...



Zitat:

Zitat von DeddyH (Beitrag 1351501)
Eine goldene Regel dafür kenne ich auch nicht, aber je dynamischer (besonders im Hinblick auf die Klassentruktur) und/oder offener (im Hinblick auf externe Schnittstellen) ein Projekt wird, desto sinnvoller wird der Gebrauch von Interfaces IMO.

Wenn man irgendwann zu einem Punkt kommt, dass man der einen Klasse ja noch die und die Klasse und der nächsten Klasse die und die bekanntgeben muss und vielleicht wegen Kreuzbezügen das gar nicht mehr hin bekommt, dann ist ein guter Zeitpunkt für Interfaces.

Wenn man schon bei der Planung eines Projektes zu dem Schluss kommt, dort irgendwann mal zu landen, dann sollte man gleich mit Interfaces starten.
So spart man sich den Aufwand der späteren Umstellung, da das doch auf einiges Auswirkungen hat.


Ich habe gerade ein nicht sehr umfangreiches Projekt der Einfachheit halber mit Klassen begonnen und habe mich jetzt doch entschieden, das nochmal umzustellen.
Das ist zwar etwas mehr Schreibarbeit aber der Ablauf und die Beziehungen der einzelnen Projektteile ist dadurch deutlich übersichtlicher.

Jim Carrey 20. Okt 2016 14:26

AW: Schon wieder: Warum Interfaces
 
Jetzt mal für ganz Dumme, also für mich:
wann Klassen, wann Interfaces?
Das mit den Autos und Reifen habe ich kein bisschen verstanden, da ich die Gedanken dahinter nicht verstehe.

Aviator 20. Okt 2016 14:30

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von stahli (Beitrag 1351503)
Wobei man Ableitungen von Interfaces eher vermeiden sollte. Hier werden ja eher Funktionalitäten beschrieben und dabei ist es i.d.R. sinnvoll, viele kleine eigenständige Funktionalitäten (Interfaces) zu definieren als von anderen abzuleiten.

Du hast mir gerade einen Anreiz gegeben, mein noch am Anfang stehendes Projekt nochmal etwas umzustrukturieren. Allerdings habe ich da dann gerade ein Verständnisproblem.

Folgender Fall:

Delphi-Quellcode:
IMyIntf1 = interface(IInterface)
  procedure SomeMethod1();
  procedure SomeMethod2();
end;

IMyIntf2 = interface(IMyIntf1) // Hier noch abgeleitet von IMyIntf1
  procedure SomeMethod3();
end;
Delphi-Quellcode:
TMyClass = class(TInterfacedObject, IMyIntf1, IMyIntf2) // Hier könnte man IMyIntf1 ja denke ich auch weglassen
  procedure SomeMethod1();
  procedure SomeMethod2();
  procedure SomeMethod3();
end;
Delphi-Quellcode:
TMyOtherClass = class(TObject)
type
private
  MyIntfInstance: IMyIntf2; // Hier die 2 beachten
  procedure CallInterfaceMethod;
end;

implementation

procedure TMyOtherClass.CallInterfaceMethod;
begin
  MyIntfInstance.SomeMethod1();  // Hier die 1 beachten.
end;
In dem Konstrukt mit der Ableitung des Interfaces 2 von 1 ist das oben gezeigte Beispiel kein Problem. Wenn ich aber jetzt
Delphi-Quellcode:
IMyIntf2
gesondert behandele und in TMyClass implementiere, dann erhalte ich ja eine Fehlermeldung, dass
Delphi-Quellcode:
SomeMethod1()
in dem Kontext nicht verfügbar ist.

Nur wie löse ich jetzt das Problem? Ich will ja jetzt nicht so viele Interfacevariablen in meiner Klasse anlegen, wie meine Interfaceklasse Interfaces importiert. Das halte ich für sehr umständlich. Ich kenne zwar vom Hören die Methode Supports(), weiß aber nicht, in wiefern das darauf anzuwenden ist.

Hat da jemand einen Tipp?

Sherlock 20. Okt 2016 14:40

AW: Schon wieder: Warum Interfaces
 
Ganz wichtig, @Jim Carey: Klassen IMMER! Interfaces dann wenn es sinnvoll ist (darüber streiten sich dann die Experten ;)) Ein Interface ersetzt keine Klasse, Interfaces sind "nur" Vorschriften darüber wie wirkliche Implementierungen auszusehen haben.

Sherlock

Jim Carrey 20. Okt 2016 14:42

AW: Schon wieder: Warum Interfaces
 
Zitat:

Zitat von Sherlock (Beitrag 1351507)
Klassen IMMER! Interfaces dann wenn es sinnvoll ist

Mit der Antwort kann ich etwas anfangen und bestätigt mich in meiner Meinung, nicht alles sofort auf Interfaces umstellen zu müssen, nur weil es sie gibt :P

Danke.

DeddyH 20. Okt 2016 14:43

AW: Schon wieder: Warum Interfaces
 
Ich mache das normalerweise so:
Delphi-Quellcode:
type
  IIntf1 = interface
    ['{AA7958DE-7A80-4F11-A5D5-A70BB3D51320}']
    procedure SomeMethod1;
    procedure SomeMethod2;
  end;

  IIntf2 = interface
    ['{A25606F4-B121-4FA5-BF07-B40C7784FFB7}']
    procedure SomeMethod3;
  end;

  TTestClass = class(TInterfacedObject, IIntf1, IIntf2)
  public
    //IIntf1
    procedure SomeMethod1;
    procedure SomeMethod2;
    //IIntf2
    procedure SomeMethod3;
  end;

{ TTestClass }

procedure TTestClass.SomeMethod1;
begin
  ShowMessage('SomeMethod1');
end;

procedure TTestClass.SomeMethod2;
begin
  ShowMessage('SomeMethod2');
end;

procedure TTestClass.SomeMethod3;
begin
  ShowMessage('SomeMethod3');
end;

procedure TFormTest.Button1Click(Sender: TObject);
var
  Test: IIntf1;
  Intf2: IIntf2;
begin
  Test := TTestClass.Create;
  Test.SomeMethod1;
  if Supports(Test, IIntf2, Intf2) then
    Intf2.SomeMethod3;
end;

stahli 20. Okt 2016 14:58

AW: Schon wieder: Warum Interfaces
 
Genau so. :thumb:

Ich will nur noch ergänzen:

Um Supports nutzen zu können muss das Interface eine Guid haben.
Und Supports liefert im letzten Parameter automatisch den Cast des übergebenen Objektes/Interfaces auf das im zweiten Parameter übergebene Interface zurück. Oder Nil wenn Supports nicht true ist.

Ich hatte mich damit (auch?) zunächst schwer getan, aber es ist eigentlich ganz simpel.

Aviator 20. Okt 2016 15:05

AW: Schon wieder: Warum Interfaces
 
@DeddyH: Danke. Super Beispiel. :thumb: Wird aber dann doch immer etwas aufwendig wenn man immer wieder mit Supports() abfragen muss. :|

Zitat:

Zitat von stahli (Beitrag 1351513)
Um Supports nutzen zu können muss das Interface eine Guid haben.

Das wa rmir bekannt, aber gut das du das für alle anderen hier auch nochmal erwähnst. :thumb:
Zitat:

Zitat von stahli (Beitrag 1351513)
Und Supports liefert im letzten Parameter automatisch den Cast des übergebenen Objektes/Interfaces auf das im zweiten Parameter übergebene Interface zurück. Oder Nil wenn Supports nicht true ist.

Ok. Das wusste ich jetzt noch nicht, wäre aber das nächste gewesen, was ich mir angeschaut hätte. :stupid:

DeddyH 20. Okt 2016 15:15

AW: Schon wieder: Warum Interfaces
 
Ob ich nun Supports() aufrufen muss oder Dinge der Art
Delphi-Quellcode:
if MyObject is TDingens then
  TDingens(myObject).Machwas;
, komfortabler wird es nicht.

[edit] Nachtrag: stahli hat Recht, man kann das übrigens auch anders formulieren.
Delphi-Quellcode:
Supports(Test, IIntf2, Intf2);
if Assigned(Intf2) then
  Intf2.SomeMethod3;
[/edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:52 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz