![]() |
Aufbau eigene Klasse mit Property und TStrings
Hallo zusammen,
in folgendem Thread habe ich nach dem Aufbau einer Anwendung/Dienst gefragt. ![]() Ich Versuche die Sache gerade mit dem Datenmodul und einer eigene Klasse zu lösen. Jetzt möchte ich einfach mal wissen, ob folgender Aufbau der unten gezeigten Klasse in Ordnung ist. Da ich sowas bislang noch nicht gemacht habe, bin ich mir z.B. mit dem Aufbau von..
Delphi-Quellcode:
nicht sicher, ob ich dort meine TStringliste.Create und .Free einbinden kann. Desweiteren würde ich mal gerne wissen, ob ich über die
constructor TMB100.create;
begin inherited; FComPortProperty := TStringlist.Create; FComPortProperty.Add('Test'); FComPortProperty.Add('Test 2'); end; //und destructor TMB100.destroy; begin FComPortProperty.Free; inherited; end;
Delphi-Quellcode:
nicht auch einen Record übergeben kann. Dies wäre den Daten die ich übergeben will näher.
Property
Hier mal die gesamte Klasse...
Delphi-Quellcode:
Vielen dank schon mal und Gruß Jens
unit mb100parser;
interface uses Classes, Graphics; type TMB100 = class constructor create; destructor destroy; private FFarbe : array [1..4] of TColor; FComPortProperty : TStrings; function GetComPortPropertys : TStrings; procedure SetColor(Nr : integer; SetFarbe : TColor); function GetColor(Nr : integer) : TColor; public property ComPortPropertys : TStrings read GetComPortPropertys write FComPortProperty; property Farbe[Nr : integer] : TColor read GetColor write SetColor; end; implementation constructor TMB100.create; begin inherited; FComPortProperty := TStringlist.Create; FComPortProperty.Add('Test'); FComPortProperty.Add('Test 2'); end; destructor TMB100.destroy; begin FComPortProperty.Free; inherited; end; function TMB100.GetComPortPropertys : Tstrings; begin Result := FComPortProperty; end; procedure TMB100.SetColor(Nr : integer; SetFarbe : TColor); begin FFarbe[Nr] := SetFarbe end; function TMB100.GetColor(Nr : integer) : TColor; begin Result := FFarbe[Nr]; end; end. |
AW: Aufbau eigene Klasse mit Property und TStrings
Das mit der Erstellung der Stringliste im Constructor und die Freigabe im Destructor ist OK.
Allerdings geht
Delphi-Quellcode:
garantiert schief, da Du beim Schreiben der Eigenschaft einfach die erstelle Stringliste überschreibst und es damit zu einem Speicherleck kommt. Normalerweise brauchst du dafür keinen Setter (also wird die Eigenschaft nur read-only). Dennoch kannst Du natürlich schreibend auf den Inhalt der Stringliste zugreifen:
property ComPortPropertys: TStrings read GetComPortPropertys write FComPortProperty;
//
Delphi-Quellcode:
Willst Du unbedingt die Eigenschaft ComPortPropertys schreibbar gestalten, mußt Du das über eine Methode machen:
property ComPortPropertys: TStrings read FComPortPropertys;
//
Delphi-Quellcode:
Zum Lesen der Eigenschaft ComPortPropertys brauchst Du übrigens keine Methode (GetComPortPropertys).
property ComPortPropertys: TStrings read FComPortPropertys write SetComPortProperty;
procedure TMB100.SetComPortProperty(Value: TStrings); begin FComPortProperty.Assign(Value); end; |
AW: Aufbau eigene Klasse mit Property und TStrings
- Methodennamen (auch Create und Destroy) werden in Delphi per Konvention Groß geschrieben
Zitat:
Zitat:
Delphi-Quellcode:
Die beiden bitte unter public und bei Destroy *immer* override angeben.
TMB100 = class
constructor create; destructor destroy;
Delphi-Quellcode:
Ich kenn deine Klasse nicht, aber warum genau 4? Haben die Zahlen ne tiefere Bedeutung?
FFarbe : array [1..4] of TColor;
Delphi-Quellcode:
Der Bezeichner scheint mir unglücklich gewählt. Es wird nicht klar, was das darstellt und warum das nun ein TStrings ist.
FComPortProperty : TStrings;
Delphi-Quellcode:
Dazu würde ja schon was gesagt.
property ComPortPropertys: TStrings read GetComPortPropertys write FComPortProperty;
Delphi-Quellcode:
Das solltest du dir genau überlegen. Du gibst damit die Interne Repräsentation nach außen. Das kann lustige Aliasing-Effekte nach sich ziehen. Sag mal mehr zu der Property.
function TMB100.GetComPortPropertys : Tstrings;
begin Result := FComPortProperty; end;
Delphi-Quellcode:
Was ist, wenn der Index nicht passt?
procedure TMB100.SetColor(Nr : integer; SetFarbe : TColor);
begin FFarbe[Nr] := SetFarbe end; function TMB100.GetColor(Nr : integer) : TColor; begin Result := FFarbe[Nr]; end; mfg Christian |
AW: Aufbau eigene Klasse mit Property und TStrings
Das write bei deinem StringList-Property weglassen
und wozu der Getter, wenn du eh nur das Feld zurückgibst?
Delphi-Quellcode:
.
property ComPortProperties: TStrings read FComPortProperty;
wenn du unbedingt write haben willst, dann implementier dieses als 'ne Assign-Methode,
Delphi-Quellcode:
PS: "ie" statt "y", wenn danach z.B. noch ein "s" folgt.
property ComPortProperties: TStrings read FComPortProperty write AssignComPortProperties;
procedure TMB100.AssignComPortProperties(Properties: TStrings); begin FComPortProperty.Assign(Properties); end; Destroy+Override und das mit der Indexprüfung wurde ja schon gesagt. |
AW: Aufbau eigene Klasse mit Property und TStrings
Zitat:
Delphi-Quellcode:
Wahrscheinlich benützt du eine Komponente für die COM-Ports.
TComPortSettings = record
ComPort : string; // z.B. 'COM3' BaudRate: Integer; // evtl. auch ein Aufzählungstyp DataBits: Integer; // 7 oder 8 Parity: Char; // N=None, E=Even, O=Odd oder evtl. auch ein Aufzählungstyp ... end; TMB100 = class ... public property ComPortSettings : TComPortSettings read FComPortSettings write FComPortSettings; property Farbe[Nr : integer] : TColor read GetColor write SetColor; end; Es kann somit ein "doppel-gemoppelt" Effekt eintreten, denn einerseits werden die Einstellungen für die serielle Schnittstelle von der Klasse TMB100 verwaltet andererseits gibt es eine COM-Port-Komponente, die ebenfalls diese Einstellungen verwaltet. Die perfekte Lösung wäre also die, dass die Klasse TMB100 die Einstellungen für die serielle Schnittstelle überhaupt nicht zu kennen braucht, sondern sie braucht nur zu wissen welche COM-Port-Komponente sie benützen soll. Stichwort: ![]() |
AW: Aufbau eigene Klasse mit Property und TStrings
Danke erstmal,
Zitat:
Delphi-Quellcode:
Zur Zeit nutze ich die Klasse über das Datenmodul. Dieses Datenmodul will ich ja später in die Service-Anwendung integrieren. Hier mal der Aufruf im Datenmodul.
unit mb100parser;
interface type ComPortProperties = record Baudrate, Parität, Flow, Start, Stop, Stopbit, Databit: string; CaseInsensitiv, Include : Boolean; end; type TMB100 = class Constructor create; Destructor destroy; override; private FComPortProperties : ComPortProperties; public property ComPort : ComPortProperties read FComPortProperties; end; implementation Constructor TMB100.create; begin inherited; FComPortProperties.Baudrate := '19200'; FComPortProperties.Parität := 'None'; FComPortProperties.Flow := 'Hardware'; FComPortProperties.Start := 'Ereignis'; FComPortProperties.Stop := #$D#$A#$A; FComPortProperties.Databit := '8'; FComPortProperties.Stopbit := '1'; FComPortProperties.CaseInsensitiv := true; FComPortProperties.Include := true; end; Destructor TMB100.destroy; begin inherited; end;
Delphi-Quellcode:
Ist der Weg so richtig?
function TDataModuleServer.SetComPort(Hardware, Port : integer) : Boolean;
var FMB100 : TMB100; begin try Result := false; case Hardware of 0: begin FMB100 := TMB100.create; case Port of 1: begin if ComPortAvailable('COM1') then begin ComPort1.Port := 'COM1'; ComPort1.BaudRate := StrToBaudRate(FMB100.ComPort.Baudrate); ComPort1.Parity.Bits := StrToParity(FMB100.ComPort.Parität); ComPort1.FlowControl.FlowControl := StrToFlowControl(FMB100.ComPort.Flow); ComPort1.StopBits := StrToStopBits(FMB100.ComPort.Stopbit); ComPort1.DataBits := StrToDataBits(FMB100.ComPort.Databit); ComDataPacket1.StartString := FMB100.ComPort.Start; ComDataPacket1.StopString := FMB100.ComPort.Stop; ComDataPacket1.CaseInsensitive := FMB100.ComPort.CaseInsensitiv; ComDataPacket1.IncludeStrings := FMB100.ComPort.Include; ComPort1.Open; if ComPort1.Connected then Result := true; end; end; //..... finally FMB100.Free; end; end; Gruß Jens |
AW: Aufbau eigene Klasse mit Property und TStrings
Zitat:
Ich habe einen Compilerschalter eingebaut, welcher mir je nach Lizenz die Klassensteuerung übernimmt. Somit bin ich mir sicher, das wirklich nur Lizenzierte Funktionen mit in die Anwendung kompiliert werden.
Delphi-Quellcode:
Gruß Jens
unit psComServMain;
{$I CompilerSchalter.inc} //... type THardware = (MB100, MB256, ESSERIQ8, BOSCHUEZ); //.. procedure TfMain.FormCreate(Sender: TObject); var Hardware : THardware; begin try Caption := FormCaption + GetVersionInfos(Application.ExeName); {$IFDEF MB100_P1}//Eine Hardware vom Typ MB100 an COM1 DataModuleServer.SetComPort(0,1);//0=MB100,1=COM1 {$ENDIF} |
AW: Aufbau eigene Klasse mit Property und TStrings
Zitat:
Zitat:
Delphi-Quellcode:
Warum denn Strings? Dafür gibts Aufzählungstypen!
Baudrate, Parität, Flow, Start, Stop, Stopbit, Databit: string;
Delphi-Quellcode:
- das Schlüsselwort "descructor" klein, der Bezeichner "Destroy" groß, nicht umgekehrt
Destructor TMB100.destroy;
begin inherited; end; - wenn du im Destruktor eh nur inherited aufrufst, brauchst du ihn nicht nochmal zu deklarieren. Er wird ja einfach geerbt
Delphi-Quellcode:
Uaah... Böser Code Smell. Bitte was soll den Hardware=0 sein? So macht man das nicht. Praktischerweise bin ich gerade dabei, einen Blog-Artikel genau über diese Problematik zu schreiben. Wenn der fertig ist (hoffentlich noch heute), sag ich dir Bescheid.
case Hardware of
0:
Delphi-Quellcode:
Auch so Konstruktionen kommen mir sehr komisch vor. Ich hab aber immer noch nicht ganz verstanden, was du vor hast.
ComPort1.BaudRate := StrToBaudRate(FMB100.ComPort.Baudrate);
Zitat:
mfg Christian |
AW: Aufbau eigene Klasse mit Property und TStrings
Ist es nicht so, dass es 4 verschiedene Hardware-Geräte gibt, die alle über die serielle Schnittstelle angesteuert werden?
Sagen wir mal es handelt sich um Alarmanlagen von verschiedenen Herstellern. 8-) Jedes Hardware-Gerät hat ein etwas anderes Datenprokoll. Aber die Gemeinsamkeit ist doch, dass immer die serielle Schnittstelle für die Kommunikation benützt wird. Man wird daher auch immer die gleiche Komponenten-Klasse für die ser. Schnittstelle benützen. Also könnte man doch folgende gemeinsame Basisklasse erstellen:
Delphi-Quellcode:
Das Property bei *) ist nun so zu verstehen:
TAlarmAnlage = class
public property ComPort : TComPort read FComPort write FComPort; // *) end; TMB100 = class(TAlarmAnlage) ... end; Ich, die Klasse TAlarmAnlage, erwarte von dem Programmierer, dass ich ein Objekt vom Typ TComPort übergeben bekomme; ansonsten kann ich nicht arbeiten. Ausserdem erwarte ich, dass der Zustand der seriellen Schnittstelle gleich "Connected" ist. Baudrate, Parity,usw. sind mir piepegal; gib' mir einfach eine aktive Komponente über die ich kommunizieren kann! Jemand, der mit der Klasse TMB100 arbeiten will muss also zuerst ein Objekt der Klasse TComPort erzeugen, dann Baudrate, Parity,usw. einstellen und die Schnittstelle öffnen. Die Klasse TAlarmAnlage machst es sich selbst ganz einfach und überträgt die Aufgabe der Initialisierung des Kommunikationsobjekts an denjenigen, der die Klasse benützen will. Was für Dich im ersten Augenblick vielleicht wie Faulheit aussieht ist Softwaretechnisch aber ein grosser Vorteil. Die Klasse könnte genausogut eine geöffnete TCP/IP-Verbindung verlangen und darüber kommunizieren ohne sich das Geringste um die IP-Adresse zu scheren. TAlarmAnlage braucht einfach nur ein Kommunikations-Objekt über das sie lesen und schreiben kann. |
AW: Aufbau eigene Klasse mit Property und TStrings
Das Problem ist etwas größer, zumindest glaube ich das, als wie es aussieht. Also ich versuche es mal zu
beschreiben. Ich habe 10 verschiedene Hardwarekomponenten (Aktuell, es können mehr werden). Zusätzlich möchte ich wenigstens, gleichzeitige 4 Verbindung über die Serielle Schnittstellen ermöglichen. Soll bedeuten, der entsprechende PC stellt die Schnittstellen COM1-COM4. Oder COM1, COM3, COM4, COM5 wie auch immer. Daraus folgt doch: Ich nehme ein Datenmodule, füge diesem 4 ComPort Komponenten zu, welche über den Dienst oder über die Anwendung konfiguriert und genutzt werden können. Das Datenmodule speichert die Empfangenen Daten in der Datenbank und liefert der Anwendung die visuelle Anzeige. Der Dienst benötigt dies ja nicht. Deshalb möchte ich dieses auch über Propertys lösen, da ich diese ja aus dem Dienst einfach nicht abfragen brauche. Die Anwendung nutzt diese Propertys. Also, 1 Anwendung oder 1 Dienst nutzen 1 Datenmodul mit der Anbindung an die entsprechende Datenbank. Dann kann das Datenmodul mit der entsprechenden Klasse kommunizieren. Soll heißen, da jede Hardware andere Einstellungen nutzt(Baudrate, Parität, Parser), verankere ich die Einstellungen doch am besten in der entsprechenden Klasse. So habe ich doch den Vorteil, einen neue Hardware, eine neue Klasse. An dem Datenmodul muss ich nichts mehr ändern. Das Datenmodul holt sich einfach aus der entsprechenden Klasse die Konfiguration der Schnittstelle. Desweiteren wird ja der Parser der entsprechenden Hardware in der Klasse implementiert. Somit habe ich alles was zur Hardware MB100 gehört in der Klasse MB100, usw. Das, so denke ich, würde zur Folge haben, das die Anwendung irgendwann fertig ist und nur noch der BUG-Beseitigung Aufmerksamkeit gespendet werden muss. Sollte eine neue Hardware notwendig sein, wird eine neue Klasse geschrieben, welche erstmal kopiert und nur noch angepasst werden muss. Die Klasse kann ins Datenmodul implementiert werden fertig. Naja, vieleicht sind das ja Traumvorstellungen. Aber so ist zur Zeit mein Überlegung. Vieleicht aber zeigt Ihr mir wo die Gedanken Fehler liegen, Gruß Jens PS: Da glaubt man, man hat viel gelesen und es verstanden, aber irgendwie ist man immer noch so dumm wie vorher. Quellen: ![]() ![]() und viele mehr.... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:11 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 by Thomas Breitkreuz