Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Mehrere Klassen von einer Klasse ableiten (https://www.delphipraxis.net/167966-mehrere-klassen-von-einer-klasse-ableiten.html)

gargano 27. Apr 2012 16:15

Mehrere Klassen von einer Klasse ableiten
 
Hallo,

ich habe schon einiges hier von abstrakten Klasse, Interfaces, Plugins gelesen, bin aber nicht so richtig fündig geworden.

Mein Problem ist folgendes:

Ich habe mehrere unterschiedliche Klassen die aber alle diegleichen Funktionen (im Interface) haben.
Die Klassen führen die Funktionen aber unterschiedlich aus.

Um auf die verschiedenen Klassen zuzugreifen habe ich im Moment eine Verzweigungsroutine z.B:
Delphi-Quellcode:
if DeviceObject.ModuleName ='Manual Inject' then begin
  TManInjectDeviceDataModule(DeviceObject.DeviceModule).InitDevice;
end;

if DeviceObject.ModuleName ='Pump4xx' then begin
            TPump4xxDeviceDataModule(DeviceObject.DeviceModule).InitDevice;
end;

if DeviceObject.ModuleName ='Pump300/500' then begin
            TPump35xxDeviceDataModule(DeviceObject.DeviceModule).InitDevice;
end;
DeviceObject ist auch eine Klasse, die dann das Object des jeweiligen Devices enthält.

Mein Problem ist jetzt, das wenn eine neue Klasse hinzukommt ich jedesmal diese Verzweigungsroutinen ändern muß.

Ziel ist es, eine Liste zu haben ( die man erweitern kann) in der die Namen der Bpl's stehen und diese bpl (für jedes Device eine eigene Bpl) dynamisch geladen wird. In diesem Falle ist diese Verzweigung nicht mehr nötig, sodaß das Hauptprogramm nicht jedesmal neu kompiliert werden muß.

Es müßte also anhand des Modulnamens auf die richtige Klasse zugegriffen werden.
Die Klasse muß auch mehrfach instanziiert werden können.

Wie kann ich das am besten und einfachsten bewerkstelligen ?

Gruß
Gargano

DeddyH 27. Apr 2012 16:28

AW: Mehrere Klassen von einer Klasse ableiten
 
Zitat:

Ich habe mehrere unterschiedliche Klassen die aber alle diegleichen Funktionen (im Interface) haben.
Die Klassen führen die Funktionen aber unterschiedlich aus.
Das klingt für mich, als bräuchtest Du eine (abstrakte) Basisklasse, von der die anderen dann abgeleitet werden.
Delphi-Quellcode:
type
  TBaseClass = class
  protected
    procedure DoSomethingImportant; virtual; abstract;
    procedure DoSomethingMoreImportant; virtual; abstract;
    procedure DoSomethingEvenMoreImportant; virtual; abstract;
  end;

  TFirstChild = class(TBaseClass)
  protected
    procedure DoSomethingImportant; override;
    procedure DoSomethingMoreImportant; override;
    procedure DoSomethingEvenMoreImportant; override;
  end;

  TSecondChild = class(TBaseClass)
  protected
    procedure DoSomethingImportant; override;
    procedure DoSomethingMoreImportant; override;
    procedure DoSomethingEvenMoreImportant; override;
  end;

procedure TMain.DoSomething(AObject: TBaseClass);
begin
  AObject.DoSomethingImportant;
end;
Je nachdem, von welchem Typ nun das übergebene Objekt ist, führt es dann die in der Ableitung implementierte Methode aus.

mkinzler 27. Apr 2012 16:29

AW: Mehrere Klassen von einer Klasse ableiten
 
Es würde imho auch ein Interface reichen

gargano 27. Apr 2012 16:48

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo DeddyH,
danke für die Antwort.
Bleibt das Problem, daß ich den Klassentyp von AObject nicht weiß , da der Typ ja in der Bpl enthalten ist und diese erst zur Laufzeit geladen wird.

Kann ich den Typ zur Laufzeit ermitteln ?
Wie wäre dann der Aufruf von TMain.DoSomething(AObject:TBaseClass) ?

mkinzler :
Von Interfaces habe ich gelesen, daß diese mit Memoryleaks Probleme haben....
Die Applikation steuert verschiedene Analysengeräte und darf nicht ausfallen. :roll:

Gruß
Gargano

DeddyH 27. Apr 2012 19:25

AW: Mehrere Klassen von einer Klasse ableiten
 
Du kannst den Typ schon zur Laufzeit ermitteln (if Dings is TBums), aber wozu? Dadurch, dass Du die Basisklasse als Datentyp übergibst (und dann ein Objekt einer davon abgeleiteten), kannst Du Dir sicher sein, dass das Objekt die richtige Methode ausführt. Zumindest, solange diese Methode überschrieben (override) wurde und nicht verdeckt. Möglicherweise verstehe ich Dich aber auch falsch.

Sir Rufo 27. Apr 2012 19:54

AW: Mehrere Klassen von einer Klasse ableiten
 
Sprecht doch mal in ganzen Sätzen mit dem TE ;)

Klassendefinition:
Delphi-Quellcode:
unit DeviceUnit;

interface

type
  TBaseDevice = class
    procedure InitDevice; virtual; abstract;
  end;

  TMainDevice = class( TBaseDevice )
    procedure InitDevice; override;
  end;

  TSubDevice = class( TBaseDevice )
    procedure InitDevice; override;
  end;

implementation

procedure TMainDevice.InitDevice;
begin
  ShowMessage('MainDevice initialisiert');
end;
 
procedure TSubDevice.InitDevice;
begin
  ShowMessage('SubDevice initialisiert');
end;

end.
Benutzung:
Delphi-Quellcode:
uses
  DeviceUnit;

procedure DoSomething( aDevice : TBaseDevice );
begin
  aDevice.InitDevice;
end;

procedure Test1;
var
  MyMainDevice : TMainDevice;
  MySubDevice : TSubDevice;
begin
  MyMainDevice := TMainDevice.Create;
  try
    DoSomething( MyMainDevice ); // -> MsgBox mit 'MainDevice initialisiert'
  finally
    MyMainDevice.Free;
  end;

  MySubDevice := TSubDevice.Create;
  try
    DoSomething( MySubDevice ); // -> MsgBox mit 'SubDevice initialisiert'
  finally
    MySubDevice.Free;
  end;
end;

procedure Test2;
var
  MyDevice : TBaseDevice;
begin
  MyDevice := TMainDevice.Create;
  try
    DoSomething( MyDevice ); // -> MsgBox mit 'MainDevice initialisiert'
  finally
    MyDevice.Free;
  end;

  MyDevice := TSubDevice.Create;
  try
    DoSomething( MyDevice ); // -> MsgBox mit 'SubDevice initialisiert'
  finally
    MyDevice.Free;
  end;
end;

gargano 28. Apr 2012 07:29

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo zusammen,

danke für die Antwort und das Beispiel.
Allerdings hat dies einen Haken: Man muß beim Kompilieren den Klassentyp kennen , hier den TMainDevice oder TSubDevice.
Nur die Klassen sind im Hauptprogramm nicht bekannt beim Kompilieren.

Nochmal zur Erklärung :
Es werden Devicemodule entwickelt, die zur Laufzeit dynamisch als bpl geladen werden (Pro Devicemodule eine Bpl) . Die Klassen in dieser bpl sind aber dem Hauptprogramm zum Zeitpunkt der Kompilierung nicht bekannt.
Also angenommen, man definiert ein neues Devicemodule mit TXDevice als Klasse. TXDevice ist in einer bpl eingebunden.
Zur Laufzeit wird die Bpl dynamisch geladen.
Welche bpl geladen wird ist in einem Ascii File eingetragen, der die Namen der bpl's enthält.
Dies geschieht alles ohne das Hauptprogramm neu zu kompilieren.

Wie kann ich nun in dem untenstehenden Beispiel TXDevice erzeugen ?
Wie kann ich also eine Klasse erzeugen, wenn ich diese nicht kenne ?

Oder sollte man hier ganz anders vorgehen ?

In dem untenstehenden Beispiel wäre dies dann so,wenn man bei abstraken Methoden bleibt :
Delphi-Quellcode:
procedure Test2;
var
  MyDevice : TBaseDevice;
begin
// TMainDevice ist hier nicht bekannt, es kann auch TXDevice
// sein oder anders.

  MyDevice := TMainDevice.Create;
  try
    DoSomething( MyDevice ); // -> MsgBox mit 'MainDevice initialisiert'
  finally
    MyDevice.Free;
  end;
Gruß
Gargano

sx2008 28. Apr 2012 07:46

AW: Mehrere Klassen von einer Klasse ableiten
 
Zitat:

Zitat von gargano (Beitrag 1163969)
Wie kann ich also eine Klasse erzeugen, wenn ich diese nicht kenne ?

Deine Klasssen müssen sich im
Delphi-Quellcode:
initialization
Abschnitt mit Hier im Forum suchenRegisterClass() bekanntmachen.
Dann kannst du später mit Hier im Forum suchenFindClass() die Klasse finden und daraus neue Objekte erzeugen.

gargano 28. Apr 2012 10:41

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo Zusammen,

jetzt habe ich mal versucht das ganze in Code umzuwandeln
Ich habe die Unit Main (Hauptprogramm), BaseUnit (abstrakte Klasse) und Unit1 (DeviceModule1).

Main :
Delphi-Quellcode:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, BaseUnit;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    MyDevice : TBaseClass;
  end;

var
  Form1: TForm1;

implementation

uses Unit1;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
        MyDevice:=TBaseClass(FindClass('TDeviceModule1'));
        TBaseClass(MyDevice).Create(Self);
end;

end.

BaseUnit:

unit BaseUnit;

interface

uses SysUtils, Classes;

type
  TBaseClass = class (TDataModule)
  protected
    procedure DoSomethingImportant; virtual; abstract;
    procedure DoSomethingMoreImportant; virtual; abstract;
    procedure DoSomethingEvenMoreImportant; virtual; abstract;
  end;

implementation

end.

Unit1:

unit Unit1;

interface

uses
  SysUtils, Classes,Forms,BaseUnit;

type
  TDeviceModule1 = class(TBaseClass)
  procedure ShowMsg (Msg:String);
    procedure DataModuleCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  DeviceModule1: TDeviceModule1;

implementation

{$R *.dfm}

procedure TDeviceModule1.DataModuleCreate(Sender: TObject);
begin
     ShowMsg('Create');
end;

procedure TDeviceModule1.ShowMsg (Msg:String);
begin
  Application.MessageBox(PChar(Msg),'Module1');
end;

initialization
RegisterClasses([TDeviceModule1]);

end.
Beim Aufruf von Button1Click im Main hat
MyDevice dann diesen Wert in der Liste der überwachten Ausdrücke :
([csSubComponent..csTransient,(außerhalb der zulässigen Bereichs) 5..(außerhalb der zulässigen Bereichs) 7])

Beim Aufruf von TBaseClass(MyDevice).Create(Self) im Main kommt es zu einer Exception.
Warum ?

Gruß
Gargano

Bummi 28. Apr 2012 11:16

AW: Mehrere Klassen von einer Klasse ableiten
 
Du benötigst noch TBaseClassClass=Class of TBaseClass;

Beispiel:
Delphi-Quellcode:
var
 c:TControl;
begin
  C := TControlClass(FindClass('TButton')).Create(Self);
  C.Parent := Self;
  C.Width := 100;
  C.Height := 100;


end;
initialization
Registerclass(TButton) ;

gargano 28. Apr 2012 12:03

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo Bummi,

danke für die Antwort, leider kann ich Dein Beispiel nicht auf mein Problem abbilden.

Könntest Du bitte
TBaseClassClass=Class of TBaseClass;
in meinem Beispiel einfügen, damit ich damit klarkomme
Danke im Vorraus.

Gruß
Gargano

Bummi 28. Apr 2012 14:31

AW: Mehrere Klassen von einer Klasse ableiten
 
Delphi-Quellcode:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, BaseUnit;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    MyDevice : TBaseClass;
  end;

var
  Form1: TForm1;

implementation

uses Unit1;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
    MyDevice:=TBaseClassClass(FindClass('TDeviceModule1')).Create(Self);
end;

end.

BaseUnit:

unit BaseUnit;

interface

uses SysUtils, Classes;

type
  TBaseClassClass=Class Of TBaseClass;
  TBaseClass = class (TDataModule)
  protected
    procedure DoSomethingImportant; virtual; abstract;
    procedure DoSomethingMoreImportant; virtual; abstract;
    procedure DoSomethingEvenMoreImportant; virtual; abstract;
  end;

implementation

end.

Unit1:

unit Unit1;

interface

uses
  SysUtils, Classes,Forms,BaseUnit;

type
  TDeviceModule1 = class(TBaseClass)
  procedure ShowMsg (Msg:String);
    procedure DataModuleCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  DeviceModule1: TDeviceModule1;

implementation

{$R *.dfm}

procedure TDeviceModule1.DataModuleCreate(Sender: TObject);
begin
     ShowMsg('Create');
end;

procedure TDeviceModule1.ShowMsg (Msg:String);
begin
  Application.MessageBox(PChar(Msg),'Module1');
end;

initialization
RegisterClasses([TDeviceModule1]);

end.

gargano 28. Apr 2012 15:20

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo Bummi,

super, das haut erstmal hin.

Eins ist noch sehr merkwürdig und führt zum Nichtfunktionieren:
TDeviceModule1 ist ja class(TBaseClass) abgeleitet von TDataModule.
In Design Tab wird auch ein TDataModule gezeigt.
Nur wenn ich das Projekt schließe und wieder öffne ist jetzt im Design Tab ein TForm abgebildet ?

Was kann das sein ?

Gruß
Gargano

himitsu 28. Apr 2012 15:23

AW: Mehrere Klassen von einer Klasse ableiten
 
Mach mal die DFM auf und schau was in der ersten Zeile drinsteht.

DFM mit einem Texteditor öffnen (die darf natürlich nicht im Binär-Format gespeichert sein ... Rechtsklick im Formeditor und Text-DFM auswählen, falls falsches Format)
oder im Form-Editor Alt+F12 drücken

gargano 28. Apr 2012 15:57

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo Bummi,

das steht da drin

Delphi-Quellcode:
object DeviceModule1: TDeviceModule1
  Left = 0
  Top = 0
  ClientHeight = 116
  ClientWidth = 207
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = DataModuleCreate
  PixelsPerInch = 96
  TextHeight = 13
end
Gruß
Gargano

himitsu 28. Apr 2012 16:13

AW: Mehrere Klassen von einer Klasse ableiten
 
Gut, das sieht OK aus.

Delphi-Quellcode:
interface

....

type
  TBaseClass = class(...
    ...
  end;

...

procedure Register;

implementation

procedure Register;
begin
  RegisterClass(TBaseClass);
end;

...
Und nun diese Unit in ein Package rein, welches du im Delphi registrierst.
(irgend wo her muß Delphi, bzw. der Formdesigner, diese Klasse auch kennen)


Ach ja, FindClass geht über eine Liste, welche mit RegisterClass befüllt wurde.
Ist die Klasse dort nicht drinn, dann kann sie nicht gefunden werden, weder von dir (FindClass), noch von dem VCL-Form-Editor.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
begin
  MyDevice := FindClass('TDeviceModule1') as TBaseClass;
  if not Assigned(MyDevice) then
    raise Exception.Create('TDeviceModule1 wurde nicht gefunden');
  TBaseClass(MyDevice).Create(Self);
end;
Genauso wie TBaseClass für den Form-Editor registriert sein muß, muß auch TDeviceModule1 dort registriert sein, wenn du es über FindClass finden/erstellen willst.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  MyClass: TBaseClassClass;
  MyDevice: TBaseClass;
begin
  MyClass := TDeviceModule1;
  MyDevice := MyClass.Create(Self);
  MyDevice.DoSomethingImportant;
  MyDevice.Free;
end;

gargano 28. Apr 2012 16:42

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo Himitsu,

wie kann es aber sein daß in einem Nachfahren von TDatamodule Eigenschaften wie Clientwidth und Font enthalten sind ?
(TDeviceModule2 ist eine Klasse von TBaseClass, die wiederum eine Klasse von TDatamodule ist)

Gruß
Gargano

himitsu 28. Apr 2012 16:54

AW: Mehrere Klassen von einer Klasse ableiten
 
Meinst du im OI oder im Quellcode (Codeverfollständigung) ?


Im OI ... wenn die VCL die falsche Klasse erwischt, bzw. es als TForm läd, obwohl es was Anderes ist.

gargano 28. Apr 2012 17:10

AW: Mehrere Klassen von einer Klasse ableiten
 
Ich meine im OI.
Was dann dazu führt, daß bei der Ausführung ein Fehler auftritt.

Wie kann ich denn das hinbringen daß es richtig ist ?

Ich bin so vorgegangen :
Ein TDatamodule erzeugt aus Datei/Neu/Weitere ->Delphi-Projekte/Delphi-Dateien/Datenmodule.

Dies erzeugt dann ein Datenmodule von TDatamodule.
Darin habe ich diese Zeile im Interface geändert
Delphi-Quellcode:
TDeviceModule1 = class(TDataModule)
in
TDeviceModule1 = class(TBaseClass)
im OI ist auch dann TDataModule vorhanden.
Soweit so gut.

Wenn ich jetzt das Projekt schließe und wieder öffne erscheint dann unter TDeviceModule1 im OI ein TForm, was ja nicht richtig ist.
Was wiederum Deine Annahme bestätigt, daß die VCL die falsche Klasse ewischt.

Evtl. ist es auch der falsche Ansatz einfach die Klasse im Code zu ändern.

Wie kann ich das richtig machen ?

Gruß
Gargano

Bummi 28. Apr 2012 17:23

AW: Mehrere Klassen von einer Klasse ableiten
 
Ich habe leider gerade keine Zugriff auf ein Delphi, vielleicht hilft Dir das weiter

http://www.delphi-forum.de/topic_Abl...e_90388,0.html
http://www.delphipraxis.net/48470-da...le-kommen.html

gargano 30. Apr 2012 12:57

AW: Mehrere Klassen von einer Klasse ableiten
 
Hallo Bummi,

funktionert leider nicht so richtig. Nach einmaligen Speichern ist wieder die TForm da.
D.h. ich kann auch da nichts später ändern.

Gibt es da eine Möglichkeit ?

Gruß
Gargano


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:35 Uhr.

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