![]() |
Brauche Objektorientierte Modellierungshilfe :-)
Hallo,
ich bin dabei eine Prüfsoftware zu entwickeln für einen Prüfstand, dieser Prüfstand besteht aus - einem PC (hier läuft die Anwendungsoftware drauf, um die es geht) - einem Prüfling (eine Hardware die u.a. auch kalibriert werden muss..) - einer Prüfplatine (mit der Prüfplatine spricht der PC direkt über USB) - einem Kalibrator (wird zum Kalibrieren des Prüflings benötigt, Kommunikation über RS232) - einem Messgerät ( wird zum zurücklesen der Ausgänge benötigt, Kommunikation über RS232) meine Frage ist nun, wie ich das Problem modellierungstechnisch angehen soll. Möglichst objektorientiert. also was ich bis jetzt habe: - 1 Klasse für den Prüfling, mit dem ich ja kommunizieren muss, um ihn testen zu können. - 1 Klasse Kalibrator - 1 Klasse Pruefplatine.. Meine Frage ist nun, wie soll ich den Prüfablauf selber koordinieren? Bisher habe ich das in der GUI gemacht (in meiner Form) also ungefähr so:
Delphi-Quellcode:
Wuerde gerne eine Pruefklasse machen, weiss aber nicht so recht wie ich diese modellieren soll.
procedure TFrmMainGUI.DoPruefung1: Boolean;
begin // Vereinfacht dargestellt, da passiert natürlich viel viel mehr in einer Prüfung Calibrator.Do4mA; // Lässt den Kalibrator 4mA am Ausgang erzeugen if Hardware.Check4mA = True then begin ShowMessage('Prüfung 1 erfolgreich'); result:=true; end else begin ShowMessage('Prüfung 1 fehlerhaft'); result:=true; end; end; Evtl. könnt ihr ja mit mir eine bessere Lösung entwickeln, als ich jetzt habe. Wäre über jede Hilfe und jeden Tipp dankbar Gruß DelphiManiac |
Re: Brauche Objektorientierte Modellierungshilfe :-)
Hi,
Objekt-Orientierter Ansatz, das klingt doch gut :wink: An sich hast Du bei der OOP wieder die Frage, was Du alles hast und was in welcher Beziehung zu einander steht. Ersteres hast Du schon ganz gut beantwortet, letzteres bleibt noch etwas offen. Der Trick bei der Modellierung liegt gerade darin, dass Du das was bestimmte Dinge gemeinsam haben auch gemeinsam und allgemein gelöst wird. Je allgmeiner, desto leichter kann es wiederverwendet werden. Natürlich musst Du es für verschiedene Fälle dann auch spezialisieren, aber auch das kennst Du ja schon! Die Frage ist hier, was genau kann gemeinsam benutzt werden und was nicht. Kann ein Prüfling von verschiedenen Kalibratoren kalibriert werden? Gibt es wieder Komponenten, die wahlweise über RS-232 oder USB kommunizieren (also auch unterschiedliche Typen, aber gleiches Gerät). Was sind die Zusammenhänge zwischen den einzelnen Dingen, was davon kann ausgetauscht werden, was gehört immer zusammen. Du weißt sicher was ich meine. Erst wenn das alles feststeht kann man schaun, was man dann wie am einfachsten modellieren kann. Gruß Der Unwissende |
Re: Brauche Objektorientierte Modellierungshilfe :-)
@Der_Unwissende:
Hi danke für deine Antwort. Mir geht es in diesem Projekt eigentlich nicht zu sehr um Wiederverwendbarkeit meiner Klassen, wohl aber um eine vernünftige Strukturierung meiner Prüfabläufe. Wie würdest du denn eine solche Prüfung aufbauen? Eine Prüfungsklasse, die die Objekte Kalibrator (mit der implementierten Kommunikation)..., Prüfling... Multimeter hat. Und dann die Prüfung durchführt?
Delphi-Quellcode:
Wäre für jede Denkhilfe dankbar.
PruefObjekt.DoTest1;
PruefObjekt.DoTest2; Gruß |
Re: Brauche Objektorientierte Modellierungshilfe :-)
Ich versuche mal eine Antwort.
Das Klassendesign kann man natürlich noch wesentlich verfeinern (so z.B. eine Basisklasse TKommunikator und dann abgeleitete Klassen wie TUSBKommunikator etc.) Wie stark du das ganze verfeinern willst, musst du während der genauen Spezifikation abschätzen. Die Hauptklasse sollte deine eigentliche Pruefung sein, auch hier könnte man entsprechend der möglichen Prüfungen das Klassenmodell weiter verfeinern. Zu einer Prüfung gehören nun einmal verschiedene Messgeräte (auch hier wieder Möglichkeiten der Verfeinerung), die entsprechenden Platinen etc. Also so ähnlich, wie du dir das wohl bereits vorgestellt hast. Ansonsten musst du natürlich beachten was der Der_Unwissende gesagt hat. Male dir die Zusammenhänge und Beziehungen einiger existierender Prüfungen auf, dann kannst du bereits etwas abschätzen was du wirklich brauchst. So hier mein Vorschlag:
Delphi-Quellcode:
Würde dann in der GUI in etwa so aussehen: // Kapselung der Kommunikationsarten (aller Geräte) // Sowohl seriell und USB sollten hier implementiert werden TKommunikator = class ... end; TKalibrator = class Kommunikation : TKommunikator; end; TMessGeraet = Class Kommunikation : TKommunikator; end; TPruefling = class Kalibrator : TKalibrator; end; TPlatine = class Kommunikation : TKommunikator; end; TPruefung = class Pruefling : TPruefling; Messgeraet : TMessGeraet; Platine : TPlatine; end; TPruefung1 = class(TPruefung) function Execute() : Boolean; end;
Delphi-Quellcode:
if cbPruefung1.checked then begin
oPruef := TPruefung1.Create(); if oPruef.Execute() then Showmessage('Prüfung 1 bestanden'); oPruef.Free(); end; |
Re: Brauche Objektorientierte Modellierungshilfe :-)
@hsg
Danke für deine ausführliche Antwort, ich finde es immer gut, wenn sich jemand Zeit nimmt eine sinnvolle und ausführliche Antwort zu verfassen, als wenn er nur schreibt macht doch einfach eine Klasse Prüfung... Aber zurück zum Thema: Dein Vorschlag ist eine Klasse Prüfung zuverwenden, die die Objekte der einzelnen Komponenten (ich meine den Kalibrator, Prüfling, Prüfplatine..) beinhaltet und davaon einzelnen Prüfklassen abzuleiten (Pro Prüfschritt eine Klasse) bzw ein daraus resultierendes Objekt. Hätte den Vorteil, dass ich jede Prüfung gleich behandeln kann. Ich muss aber während meine Prüfablaufs auch eine optische darstellung machen, also z.B.: das Kalibrieren, der Kalibrator gibt einen Wert vor (sagen wir mal 20mA) und ich muss mit dem Prüfling kommunizieren ob er diese 20mA erkannt hat und ob der Wert sauber steht, d.h. nicht schwankt um dann den Sensorwert abzuspeichern. Wie kann ich dass dann in meiner Prüfklasse am Besten bewerkstelligen. Hoffe ihr versteht was ich meine. Danke schonmal im Vorraus :-) |
Re: Brauche Objektorientierte Modellierungshilfe :-)
Schau dir mal den Sourcecode von
![]() Dort wird OO im Extrem betrieben; dir wird es sicher erst mal "den Zwölfer raushauen". Aber du kannst vieles abschauen wie z.B. die Baumstruktur der Testfälle. Wenn es dir darum geht, einen Prüfling zu testen und zum Schluss als Ergebnis OK oder Fehlerhaft zu erhalten (plus Information, welche Tests fehlgeschlagen sind), dann könntest du sogar DUnit direkt verwenden. Mit DUnit testet man normalerweise die Funktionsfähigkeit von eigener Software. Man könnte aber auch Hardware oder Prüflinge (DUTs) testen. |
Re: Brauche Objektorientierte Modellierungshilfe :-)
Zitat:
Den Ansatz den Hsg hier vorgeschlagen hat, den finde ich schon mal ganz gut! Was Du klar ausnutzen kannst ist die Tatsache, dass Du immer einen gleichen Ablauf hast. Den solltest Du einfach mal ganz abstrakt betrachten. Ich weiß jetzt nicht genau, wie Prüfling, Prüfplatine usw. mit einander zusammen hängen. Das sind eben die Info's, die schon wichtig für die Modellierung wären. Du hast ja offensichtlich immer ein Tupel aus Prüfling und Kalibrator. Ggf. kannst Du natürlich auch eher das Tripel Prüfplatine, Prüfling und Kalibrator haben (wenn es mehrere Prüflinge auf der gleichen Platine geben kann oder die aus anderen Gründen adressiert werden). Jedenfalls ist hier eine einfache Möglichkeit, dass Du für das, mit dem Du direkt kommunizierst eine Klasse baust. Diese können (sollten?) von einer Basisklasse abgeleitet werden, in der die Methoden erstmal abstrakt sind. In die Basisklasse kommen dabei Methoden, die für alle Prüfungen benötigt werden. Z.B. setze Wert bei der Prüfplatine und leseWert bei dem Messgerät. Von diesen Basisklassen leitest Du dann einfach die konkreten Klassen (spezielle Prüfplatine und spezielles Messgerät) ab. Jetzt hast Du zwei getrennte Klassen, eine dient dem setzen eines Werts, die andere dem Auslesen. Eine Messung sieht jetzt aber auch immer sehr gleich aus, ganz allgemein (wie Du es schon aufgeschrieben hast!) geht es um folgendes:
Soweit sieht das für alle Messungen noch recht gleich aus! Das kannst Du dann wieder einfach ausnutzen, indem Du hier eine eigene Klasse (TMessung) draus machst. Diese macht dann nichts anderes als das, was dort drin steht. Natürlich ist auch diese Klasse erstmal abstrakt und es gibt dann konkrete Ausprägungen. Ich gehe hier einfach mal davon aus, dass es sich bei den verschiedenen Messungen immer darum handelt, dass Du bestimmte Werte als Fließkomazahl setzt und entsprechend wieder ausliest. Sagen wir mal einfach, Du hast eine I/O-Karte als Prüfling, die eine bestimmte Spannung, einen Wiederstand und eine Stromstärke zur Verfügung stellen kann (mir egal ob das Sinn macht!) und dann noch ein Multimeter, dass Dein Messgerät darstellt. Die Messungen bestehen dann daraus, dass x-Volt, y-Ampere oder z-Ohm "angelegt" und gemessen werden sollen. Anders gesagt gibt es eine Spannungs, eine Stromstärke und eine Wiederstandsprüfung. Nur um es zu sagen, alles hier gesagt lässt sich leicht (hoffe ich) auf verschiedene Messwerte einer Art übertragen! Gut, diese drei Messungen laufen also im Prinzip gleich ab, man ruft die Methode setzeWert der Prüfplatine auf, wartet eine bestimmte Zeit (auch 0), misst n-mal (n >=1) den anliegenden Wert, speichert die gelesenen Werte zwischen, bildet Mittelwert, Std.Abweichung, Varianz, ... Der Unterschied zwischen den Messungen liegt nur darin, welche Prüfplatine verwendet wird (besser welcher Prüfling) und welches Messgerät. Natürlich kann das Messgerät die ganze Zeit das gleiche Multimeter sein, nur die Art der Messung variiert, aber es kann halt virtuell als echt unterschiedliche Geräte aufgefasst werden. Auch die Zeit die nötig ist, bis eine bestimmte Spannung oder Stromstärke gemessen werden kann ist natürlich variabel. Trotzdem sind dies nur Parameter, die gesetzt werden müssen, der Ablauf ist dann immer gleich. Hier kannst Du leicht über Dependency-Injection nachdenken. So benötigt jede Messung eben einen Prüfling/eine Prüfplatine und ein (passendes) Messgerät. Beides kannst Du in einer anderen Klasse (z.B. eine Fabrik) erzeugen und an die Messklasse übergeben. Klingt alles etwas kompliziert, ist es aber gar nicht! Mal am Beispiel:
Delphi-Quellcode:
Damit hast eine abstrakte Prüflingsklasse. Die bietet einfach eine Methode setValue an, die dafür sorgt, dass der Prüfling diesen Wert bereitstellt. Ist der Prüfling eben eine Spannungsquelle, wird der Wert in Volt ausgegeben, als Wiederstand währe es der Wiederstand in Ohn, als Stromquelle der Strom in Ampere. Die Klassen, die von TPruefling abgeleitet sind können natürlich noch jede Menge anderer Methoden und variablen enthalten! Wichtig ist nur, dass alles was ein TPruefling ist über die Methode setValue seinen Wert gesetzt bekommen kann!
// Erstmal die Prüflinge
type TPruefling = class(TObject) public // Abstrakte Methode, setzt eben einen Wert procedure setValue(const Value: Double); virtual; abstract; end; TSpannungsPruefling = class(TPruefling) public // implementiert die abstrakte Methode // hier also die Kommunikation, die nötig ist damit der Prüfling diesen Wert ausgibt/einstellt/... procedure setValue(const Value: Double); override; end; TWiederstandsPruefling = class(TPruefling) public // implementiert die abstrakte Methode // hier also die Kommunikation, die nötig ist damit der Prüfling diesen Wert ausgibt/einstellt/... procedure setValue(const Value: Double); override; end; ... Beim Messgerät sieht es ganz analog aus:
Delphi-Quellcode:
Ja, ich denke soweit ist eigentlich noch alles klar. Der eigentlich Trick kommt erst jetzt. Nun kann man die Messklasse erstellen, die eben etwas abstrakter arbeiten kann. Ihre Aufgabe sind die vorhin genannten Punkte, sie hat einen Prüfling und ein Messgerät (die zusammenpassen!) und macht nichts anderes als einen Wert anzulegen, zu warten, den aktuellen Wert (mehrfach) zu messen und dann irgendwas zu berechnen (hier mal einfach Mittelwert + Std. Abweichung).
type
TMessgeraet= class(TObject) public // Abstrakte Methode, liest den aktuellen Wert function getValue: Double; virtual; abstract; end; TSpannungsMessgeraet= class(TMessgeraet) public // implementiert die abstrakte Methode // hier also die Kommunikation, die nötig ist damit das Messgerät den aktuellen Wert liest function getValue: Double; override; end; TWiederstandsMessgeraet= class(TMessgeraet) public // implementiert die abstrakte Methode // hier also die Kommunikation, die nötig ist damit das Messgerät den aktuellen Wert liest function getValue: Double; override; end; ... Das ganze könnte so aussehen:
Delphi-Quellcode:
Ich hoffe es ist soweit schon klar, was gemacht wird. An sich hier der Hinweis, dass das nicht ganz sauberer Code ist! Das sleep sollte man nicht wirklich verwenden und es wäre auch sinnvoll die Gültigkeit des Wertes zu prüfen, zu schauen ob ein Messgerät und Prüfling übergeben wurden (<> nil/assigned), schauen dass auch überhaupt > 0 Messungen durchgeführt werden sollen, usw.
type
TTestKlasse = TObject private FPruefling: TPruefling; FMessgeraet: TMessgeraet; FWartezeit: Cardinal; public constructor create(const Pruefling: TPruefling; const Messgeraet: TMessgeraet; const Wartezeit: Cardinal = 0); destructor destroy; override; procedure fuehreMessungAus(const Wert: Double; const AnzahlMessungen: Cardinal; const WartezeitZwischenMessungen: Cardinal; out Mittelwert: Extended; out StdAbweichung: Extended); end; .... constructor TTestKlasse.create; begin inherited create; // speichern der übergebenen Werte/Referenzen self.FPruefling := Pruefling; self.FMessgeraet := Messgeraet; self.FWartezeit := Wartezeit; end; denstructor TTestKlasse.destroy; begin // Freigabe self.FPruefling.Free; self.FMessgeraet.Free; inherited; end; procedure TTestKlasse.fuehreMessungAus(const Wert: Double; const AnzahlMessungen: Cardinal; const WartezeitZwischenMessungen: Cardinal; out Mittelwert: Extended; out StdAbweichung: Extended); var results: Array of Double; i: Cardinal; begin // Anlegen des Wertes an Pruefling self.FPruefling.setValue(Wert); // Warten bis Wert sicher stabil anliegt (liegen sollte) // hier mal ein gaaanz unschöner weg, besser delay aus der DP! sleep(self.FWartezeit); // Ausführen der Kontrollmessungen setLength(results, AnzahlMessungen); for i := 0 to anzahlMessungen - 1 do begin results[i] := self.FMessgeraet.getValue; // Wartezeit zwischen zwei Messungen abwarten // hier mal ein gaaanz unschöner weg, besser delay aus der DP! sleep(WartezeitZwischenMessungen); end; // berechnen von Mittelwert und Std.Abweichung // Methode aus Unit Math, sehr flink! MeanAndStdDev(results, Mittelwert, stdAbweichung); end; Hier geht es aber nur um die Idee. Man hat einfach eine Testklasse, die immer die gleichen Schritte für ein beliebiges Tupel aus Messgerät und Prüfling ausführt. Um welchen Prüfling und welches Messgerät es sich dabei genau handelt legt der Konstruktor fest. Der nächste Schritt besteht dann einfach darin, dass Du eine Klasse schaffst, die entsprechende Objekte erzeugt:
Delphi-Quellcode:
Die Variablen spannungsmessung und stromstärkenmessung sind vom Typ TTestKlasse und haben somit die Methode fuehreMessungAus. Der übergibst Du dann die Spannung oder die Stromstärke, die Du messen möchtest, die jeweilige Anzahl der Messungen usw., den Rest erledigt die für Dich. Dabei wird in der spannungsmessung wirklich eine Spannung angelegt und gemessen, bei der stromstärkenmessung eben eine Stromstärke. Wie gesagt, Du kannst das leicht an nur Spannungen, dafür aber unterschiedliche Werte, anpassen (oder eben später an andere Prüflinge/Messgeräte!).
spannungsmessung := TTestKlasse.create(TSpannungsPruefling.Create,
TSpannungsMessgerät.Create, 0); stromstärkenmessung := TTestKlasse.create(TStromstärkenPruefling.Create, TStromstärkenMessgerät.Create, 10); ... Und um auf Deine eigentliche Frage zu sprechen zu kommen, natürlich kannst Du auch mehr als eine Methode anbieten oder die mehr als das hier machen lassen. Soll jede Messung auch etwas zeichnen, dann kannst Du auch dafür in der TTestklasse einem Methode vorsehen. Die könnte z.B. noch zusätzlich einen Canvas übergeben bekommen und eine Zeichenklasse. Die Zeichenklasse macht dann nicht mehr als bestimmte Dinge auf den Canvas zu zeichnen. Ist diese abstrakt, kannst Du natürlich für Spannung und Stromstärke wieder konkrete Implementierungen erzeugen, die unterschiedliche Dinge zeichnen. Interessieren Dich nur die Abweichungen (ohne Einheiten) kannst Du natürlich auch auf eine einzelne Zeichenklasse, die immer das gleiche macht zurückgreifen. Ich hoffe das die Ideen grob klar sind (vielleicht nicht so schön wie bei DUnit, aber hoffentlich trotzdem hilfreich!). Ansonsten einfach weiter nachfragen! Gruß Der Unwissende |
Re: Brauche Objektorientierte Modellierungshilfe :-)
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,
ich wollte hier mal das Prüf-Organigramm darstellen, damit man es sich auch mal bildlich vorstellen kann :-) Generell gibt es eine Kommunikation über USB mit dem Prüfling, desweiteren eine Kommunikation zum Kalibrator und über den selben Kanal an das Multimeter. Der Kalibrator und das Multimeter fahren eine ASCII-Protokoll, um jetzt z.B.: mit dem Multimeter zu sprechen, wird dem Kalibrator ein String vorangestellt, so weiss er, dass er es weiter rausschieben (über seine 2. Schnittestelle) muss. Also hier das Bild: |
Re: Brauche Objektorientierte Modellierungshilfe :-)
Hallo,
bevor meine Prüfung starten kann muss ich mein Gerät (Prüfling) parametrieren. Das heißt ich habe eine Parameterdatei (eine INI). Dessen Werte ich in das Gerät übertragen muss. Ich habe das bisher folgendermaßen (nicht sehr schön, und vorallendingen nicht sehr objektorientiert, wohl eher funktional) gemacht: INI sieht folgendermaßen aus [Benutzerdaten] AnalogOut=200 AnalogOn=1 ... [...] ... Ich habe hier in der Paramerdatei ungefähr 200 Werte die ins Gerät geschrieben werden müssen, und die hardcodiert Aufzählung an sich finde ich nicht gut hier Ich habe eine Funktion zur Übertragung der Datei gebaut: Folgender Aufbau:
Delphi-Quellcode:
D.h.
TGeraet.WriteParameterToDevice(Paramertername:string);
var aParDatei:TINiFile; section:string; ident:string; aDouble:Double; aInt:Integer; aString:string; begin aParDatei:=TIniFile.Create(ParDatei); ////////////Benutzerdaten///////////////////// section:='Benutzerdaten'; if aParDatei.SectionExists(section) then begin ////////////AnalogOut///////////////// ident:='AnalogOut'; if aParDatei.ValueExists(section,ident) then begin aInt:=aParDatei.ReadInteger(section,ident,0); result:=Set_AnalogOut(aInt); //<-- Das hier ist die API Funktion um den Wert in das Gerät zu speichern... if NOT(Result = 0) then exit; end; ...... end; ich habe als Übergabeparameter den Dateinamen und habe in der Funktion die Parameter hardcodiert und überprüfe ob sie existieren, und schreibe sie dann ins Gerät. Jedoch will ich ja auch einen aussagekräftigen Rückgabewert haben. Wie kann ich das bewerkstelligen, denn es kann ja folgendes auftreten. 1.Section existiert nicht 2.Ident existiert nicht 3. Parameter wird nicht erfolgereich ins Gerät geschrieben.. (Rückgabewert der API Funktion <> 0) Wie bekomme ich das objektorientiert gelöst. Wäre über Anmerkungen und Hilfestellungen sehr dankbar. Gruß DelphiManiac |
Re: Brauche Objektorientierte Modellierungshilfe :-)
*push*
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:08 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz