objektorientierte Programmierung - komponentenbasierte Programmierung

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

Moin,

eigentlich könnte ich mich auch an
viewtopic.php?f=9&t=13411
anhängen denn meine Frage geht - möglicherweise - in eine ähnliche Richtung, siehe :
charlytango hat geschrieben:
Sa 6. Feb 2021, 19:34
Nun ist mein Ziel die Klasse TXY einfacher handhabbar zu machen -- also wenn nötig die Unit der Klasse TXY einzubinden ohne immer einen zusätzlichen Unit-Rattenschwanz mitzuführen. Gleichzeitig möchte ich aber ..
Segen und Fluch der objektorientierten Programmierung ist die Vererbung.
Die zieht einen Rattenschwanz an Units mit sich, von denen man sich nicht lösen kann.
Ich will's mal an einem Beispiel erklären:

Ich habe - mal angenommen - eine Audio-Software (DAW), die hat verschiedene Funktionalitäten
- Bedienoberfläche (GUI)
- Audio-Engine (I/O Interfaces und DSP-Kram)
- File-Management (gleichzeitige Nutzung vieler Files)
- Handling verschiedener File-Formate
- ... und keine Ahnung, was noch alles ..

Jetzt möchte ich mal nur diese Audio-Engine auch in einem anderen Programm verwenden.
Durch Querbeziehungen zwischen GUI, Audio-Engine und File-Management
ziehe ich beim einbinden eines einzigen TObjects ggf. den gesamten Rattenschwanz an Units mit,
die ich gerne getrennt lassen wollte. Es wird irgendwann ein nicht mehr entwirrbares Kneuel von Sourcecode.

Der Haken scheint mir zu sein, daß mir PASCAL (Lazarus) OOP hier vom Konzept her keine Hilfestellung gibt.
Ich kann nicht mal eben - unterstützt von der Sprache - eine unabhängige "Komponente" definieren, siehe auch
https://de.wikipedia.org/wiki/Komponent ... ntwicklung
https://de.wikipedia.org/wiki/Komponent ... ittstellen

Lazarus / Pascal ist leider keine "komponentenbasierte Sprache", sondern "nur" eine objektorientierte.


Meine aktuelle Idee wäre, die Kette der Vererbung ganz weit unten aufzubrechen.

1) Eine Basis-Klasse schreiben, die nur das Interface des TBasisObjekts definiert.
Diese Unit kann ich ohne großen Rattenschwanz überall einbinden.

2) darauf aufbauend das voll funtionierende abgeleitete TMyObject schreiben, das Interface muß aber gleichbleiben.
Ich darf also in abgeleiteten TMyObjects keine Definitionen in public und published hinzufügen, löschen oder überschreiben.

3) In der GUI könnte ich z.B. ein TBasisObjekt als Variable anlegen, damit sind in der GUI
die public und published Funktionen, Variablen etc. von TBasisObjekt bekannt und verfügbar.
Um ein von TBasisObjekt abgeleitetes Objekt zu benutzen, muß ich dann einen Pointer umbiegen:

Code: Alles auswählen

PZumInterfaceVonTMyObject:= TBasisObjekt( @MeineAbgeleiteteKlasse);
( Pseudo-Code .. nur zur Erläuterung )


Ich will das in der nächsten Zeit mal ausprobieren, also ein Dummy-Beispiel-Projekt aufsetzen,
um zu schauen, ob das tatsächlich klappen würde.

Oder gibt es da bereits komponenten-basierte Ansätze, von denen ich noch nichts gelesen habe ?
Zuletzt geändert von PeterS am So 21. Feb 2021, 11:39, insgesamt 2-mal geändert.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6200
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von af0815 »

Grundlegend gibt es noch die Idee, nur auf Interfaces zu programmieren. Damit ist man noch flexibler und komplett entkoppelt. Ist aber wieder weg von der Idee des RAD.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

Soweit ich das verstanden habe, sind Interfaces ja ein definierter Bestandteil von "komponentenorientieren Sprachen".
Das wird aber halt vom objektorientierten Ansatz nicht aktiv unterstützt ..

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

Ich habe gerade diesen Artikel gelesen ..
https://de.wikipedia.org/wiki/Abstrakte_Klasse

und ehrlich gesagt habe ich mich damit nie befaßt.

Wären vielleicht abstrakte Basisklassen ein gangbarer Weg,
um Lazarus- (Pascal-) TObjects voneinander zu "entkoppeln" ?

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von wp_xyz »

Die ganze Theorie hilft dir nichts, wenn der Package-Autor seine Bibliothek nicht klar strukturiert und überall Querverbindungen zwischen den Units einbaut. Ich kenne die von dir genannte Bibliothek nicht, aber wenn die Audio-Engine so geschrieben ist, ohne dass Bezüge zu den Bedienelemente vorkommen, dann könntest du ein eigenes Package erstellen, in dem nur die Audio-Engine enthalten ist (vereinfach ausgedrückt, natürlich).

Ich glaube, das ganze ist eher ein Problem der Package-Struktur und der Abhöngigkeiten der Units innerhalb des Packages als ein grundsätzliches Problem von OOP. Und auch ein Problem des Überfrachtens von Bilbiotheken mit immer mehr Funktionalitäten, anstatt neue Funktionalitäten in andere Packages auszulagern

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

wp_xyz hat geschrieben:
So 21. Feb 2021, 12:35
Die ganze Theorie hilft dir nichts, wenn der Package-Autor seine Bibliothek nicht klar strukturiert und überall Querverbindungen zwischen den Units einbaut. Ich kenne die von dir genannte Bibliothek nicht, aber ..
Ich hatte keine konkrete Bibliothek genannt, oder "im Auge".
Mir geht es darum, wie ich selber meine eigenen Programm-Objekte
aufbauen muß damit ich mich nicht selber in diesen Abhängigkeiten verhedder ..

Mir fiel da gerade das folgende Beispiel ein:

Code: Alles auswählen

    ShellListView1: TShellListView;
    ShellTreeView1: TShellTreeView; 
Die verbinden sich über ein Property miteinander, das man im Objekt-Inspector setzen kann.
Aber da ist es ja kein Problem da beide TObjects ja dasselbe Thema behandeln: Dateimanagement.
Da ist es dann egal daß beide TObjects dieselben Units "mitschleppen".

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von wp_xyz »

Ich verstehe nicht so recht, was du konkret erreichen willst. TShellListView und TShellTreeView sind in derselben Unit, beide ergänzen sich optimal. Ist deine Frage: Wie kann ich ShellTreeView verwenden, ohne dass ich ShellListView mitgeliefert bekomme? Zum einen hilft der Compiler, der die definitiv nicht aufgerufenen Routinen der ShellListView nicht einbindet, evtl kann man noch mehr mit SmartLinking erreichen. Wenn das nicht reicht, kann ich nur sagen: selbst machen (und dich im drei Jahren ärgern, warum du damals ShellTreeView nicht so schlau gemacht hast, es mit einer ShellListView zusammenarbeitet...)

Fazit: Wenn Komponenten vielseitig verwendbar sein sollen, dann müssen sie halt etwas mehr Code mitschleppen als spezialisierte Versionen, die auf den konkreten Anwendungsfall zugeschnitten sind.

Was ich mit meinem Post oben sagen wollte, ist, dass Biliotheken im allgemeinen aus vielen Units bestehen, dass aber die Abhängigkeiten der Units untereinander oft nicht optimal ausgelegt sind. Zum Beispiel könnte man Funktionalitäten viel besser isolieren, wenn man vielleicht eine Deklaration aus der einen Unit in eine andere verlegen oder eine Gruppe von Funktionen in eine separate Unit auslagern würde. Letzteres passiert z.Zt in Lazarus, da wird viel allgemeine Funktionalität aus der LCL in das Package LazUtils ausgelagert, so dass diese Funktionen aufrufbar sind, ohne die ganze LCL im Boot zu haben.

PascalDragon
Beiträge: 825
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PascalDragon »

PeterS hat geschrieben:
So 21. Feb 2021, 11:11
Segen und Fluch der objektorientierten Programmierung ist die Vererbung.
Die zieht einen Rattenschwanz an Units mit sich, von denen man sich nicht lösen kann.
Ich will's mal an einem Beispiel erklären:

Ich habe - mal angenommen - eine Audio-Software (DAW), die hat verschiedene Funktionalitäten
- Bedienoberfläche (GUI)
- Audio-Engine (I/O Interfaces und DSP-Kram)
- File-Management (gleichzeitige Nutzung vieler Files)
- Handling verschiedener File-Formate
- ... und keine Ahnung, was noch alles ..

Jetzt möchte ich mal nur diese Audio-Engine auch in einem anderen Programm verwenden.
Durch Querbeziehungen zwischen GUI, Audio-Engine und File-Management
ziehe ich beim einbinden eines einzigen TObjects ggf. den gesamten Rattenschwanz an Units mit,
die ich gerne getrennt lassen wollte. Es wird irgendwann ein nicht mehr entwirrbares Kneuel von Sourcecode.
Dann hast du es aber schon schlecht designed. Du solltest die Audio-Engine so gestalten, dass sie keine Abhängigkeiten zur GUI hat, bzw. wenn überhaupt diese durch Interfaces, abstrakte Klassen oder Ereignisse bereitstellt. Genauso kannst du es so gestalten, dass der Dateizugriff durch entsprechende Mechanismen abgedeckt ist. Hierdurch kannst du die Engine separat nutzen (und auch testen, falls du Unittests verwendest).
FPC Compiler Entwickler

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

wp_xyz hat geschrieben:
So 21. Feb 2021, 16:17
Ich verstehe nicht so recht, was du konkret erreichen willst. TShellListView und TShellTreeView sind ..
Mich interessieren TShellListView und TShellTreeView nicht.
Ich habe sie nur als Beispiel genannt.

Mit "komponentenbasierte Programmierung" sind hier nicht die Komponenten in Delphi oder Lazarus gemeint.

Lies doch mal meinen Eingangs-Post.
Zuletzt geändert von PeterS am So 21. Feb 2021, 18:22, insgesamt 4-mal geändert.

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

PascalDragon hat geschrieben:
So 21. Feb 2021, 16:54
Dann hast du es aber schon schlecht designed. Du solltest die Audio-Engine so gestalten, dass sie ..
Ich habe noch garnichts designt.

Meine Frage wäre, wie man es hinbekommt, ohne vorhandene Unterstützung seitens der Sprache PASCAL
unabhängige Lazarus-TObjects zu erstellen, die sich wie in komponentenbasierter Programmierung verhalten.
=> https://de.wikipedia.org/wiki/Komponentenmodell

Und mit "Komponenten" sind hier nicht die Komponenten in Delphi oder Lazarus gemeint.

PascalDragon hat geschrieben:
So 21. Feb 2021, 16:54
.. wenn überhaupt diese durch Interfaces, abstrakte Klassen oder Ereignisse bereitstellt.
Das fehlt mir in meinem "Werkzeugkasten".

=>
PeterS hat geschrieben:
So 21. Feb 2021, 12:09
Wären vielleicht abstrakte Basisklassen ein gangbarer Weg,
um Lazarus- (Pascal-) TObjects voneinander zu "entkoppeln" ?

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

af0815 hat geschrieben:
So 21. Feb 2021, 11:33
Grundlegend gibt es noch die Idee, nur auf Interfaces zu programmieren. Damit ist man noch flexibler und komplett entkoppelt. Ist aber wieder weg von der Idee des RAD.
Kannst Du mir erklären wie Du das meinst mit den "Interfaces", in Lazarus ?
..
Okay, habe da gerade was gefunden, aber das kenne ich überhaupt noch nicht ..
https://wiki.freepascal.org/Interfaces
https://wiki.freepascal.org/Understanding_Interfaces

Ein mir bislang unbekanntes Konstrukt, und dann noch in Englisch .. puh !


EDIT: hab was gefunden - https://de.wikibooks.org/wiki/Programmi ... Interfaces
Ich hoffe, das hilft mir weiter ..

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6200
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von af0815 »

zum Thema gegen Interfaces programmieren wirst du auf Deutsch nichts finden.

Generell kannst du dir ein Interface wie einen Kontrakt (Vereinbarung) vorstellen. Du kannst dann jeden verwenden der dir den Kontrakt erfüllt. Ein extremes windowslastiges Beispiel ist Directshow. Da programmierst du nur gegen Interfaces. Total genial, aber extrem kompliziert.

Leider ist die Programmierung gegen Interfaces noch nicht 100 Prozent in der visulellen Unterstützung von Lazarus verankert. Kann aber sein, das sich da etwas in den letztem 3 Jahren geändert hat.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

af0815 hat geschrieben:
So 21. Feb 2021, 19:32
Generell kannst du dir ein Interface wie einen Kontrakt (Vereinbarung) vorstellen. Du kannst dann jeden verwenden der dir den Kontrakt erfüllt. Ein extremes windowslastiges Beispiel ist Directshow. Da programmierst du nur gegen Interfaces. Total genial, aber extrem kompliziert.
Ich habe gerade DirectShow8.pas in meinem Repository gefunden,
und da auch "Interface"- Deklarationen gesehen.
Ist mir aber zum nur mal ausprobieren jetzt zu komplex.

Daher habe ich das Beispiel von https://de.wikibooks.org/wiki/Programmi ... Interfaces
mal in ein GUI Programm gegossen.

Entscheidende Funktion hier ist ButtonTestClick()

Code: Alles auswählen

unit MainUnit;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
  TestInterfaceUnit;

type

  { TForm1 }

  TForm1 = class(TForm)
    ButtonTest: TButton;
    ButtonClose: TButton;
    Memo1: TMemo;
    procedure ButtonCloseClick(Sender: TObject);
    procedure ButtonTestClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
  private
    //
  public
    Tankstelle1: TErsteTankstelle;
    Tankstelle2: TZweiteTankstelle;
  end;


var
  Form1: TForm1;

implementation

{$R *.lfm}


function HoleTankpreis(Liter: Single; Tankstelle: ITankstelle): Single;
begin
  try
    Result := Tankstelle.BerechnePreis( Liter);
  except
    ShowMessage( 'Die Tankstelle wurde nicht gefunden');
    Result := 0;
  end;
end;


{ --- TForm1 ----------------------------------------------------------------- }
procedure TForm1.FormCreate(Sender: TObject);
begin
  Tankstelle1:= TErsteTankstelle.Create;
  Tankstelle2:= TZweiteTankstelle.Create;
end;


procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  // Quatsch ?
  //Tankstelle1.Free;
  //Tankstelle2.Free;
end;


procedure TForm1.ButtonTestClick(Sender: TObject);
begin
  Memo1.Clear;
  Memo1.Append( FloatToStr( HoleTankpreis( 50, Tankstelle1) ));
  Memo1.Append( FloatToStr( HoleTankpreis( 50, Tankstelle2) ));

  TRY
    Tankstelle1:= TErsteTankstelle.Create;
    Memo1.Append( FloatToStr( HoleTankpreis( 50, Tankstelle1) ));
  EXCEPT
    ShowMessage( 'Exception on second call of Tankstelle1 ..');
  end;
end;


procedure TForm1.ButtonCloseClick(Sender: TObject);
begin
  Close;
end;


end.
Beim schließen der Form, also bei Tankstelle1.Free;
stürzte das Programm ab, daher hab ich es auskommentiert ..
Zuletzt geändert von PeterS am So 21. Feb 2021, 20:14, insgesamt 5-mal geändert.

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

Und hier die Unit

Code: Alles auswählen

unit TestInterfaceUnit;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

type
  ITankstelle = interface
      function BerechnePreis(Liter: Single): Single;
    end;

    TErsteTankstelle = class(TInterfacedObject, ITankstelle)
    function BerechnePreis(Liter: Single): Single;
  end;

  TZweiteTankstelle = class(TInterfacedObject, ITankstelle)
    function BerechnePreis(Liter: Single): Single;
  end;



implementation


function TErsteTankstelle.BerechnePreis(Liter: Single): Single;
begin
  Result := 1.5 * Liter;
end;


function TZweiteTankstelle.BerechnePreis(Liter: Single): Single;
begin
  Result := 1.3 * Liter;
end;


end.

PeterS
Beiträge: 34
Registriert: So 22. Feb 2015, 11:36
OS, Lazarus, FPC: 2.0.10
CPU-Target: win32

Re: objektorientierte Programmierung - komponentenbasierte Programmierung

Beitrag von PeterS »

Das hier ..

Code: Alles auswählen

  Tankstelle1:= TErsteTankstelle.Create;
  Tankstelle2:= TZweiteTankstelle.Create;
scheint in FormCreate() falsch zu sein,
muß man tatsächlich sowas wie

Code: Alles auswählen

Tankstelle1:= TErsteTankstelle.Create;
vor jedem Aufruf des Interfaces machen ?

Und kein Tankstelle1.Free; ???
Scheint ja ein recht flüchtiger Geselle zu sein, dieser INTERFACE ..


EDIT: hab gerade gelesen .. "Schnittstellen enthalten keine Konstruktoren und Destruktoren."

Antworten