Hallo, Auf eine Klasseninstanz / Objekt soll in verschiedenen Klassen in verschiedenen Files zugegriffen werden können. Ich sehe jetzt nur die Möglichkeiten..... Verwenden von extern oder durchreichen von Pointern auf das Objekt oder die Klasse als Sinleton anzulegen. Am saubersten aber aufwendigsten wäre wohl das Durchreichen von nem Pointer auf das Objekt, auf das ich in der jeweiligen Klasse zugreifen will. Singleton ginge wäre aber wohl zweckentfremdet. Extern ginge auch.... aber ... unsauberer? Gibt es Alternativen oder was wäre die gute Lösung?
Wie immer ist die Antwort auf die Frage "welcher Pattern passt" halt "kommt drauf an". Singleton ist ok, wenn du dir absolut, 100% sicher bist, dass es nie Sinn macht dass es mehrere dieser Objekte gibt. Plausibler Kandidat wären z.B. die globalen Konfigurationsoptionen des Programms. In allen anderen Fällen macht durchreichen erfahrungsgemäß mittelfristig weniger Ärger.
Janosch schrieb: > Am saubersten aber aufwendigsten wäre wohl das Durchreichen von nem > Pointer auf das Objekt, auf das ich in der jeweiligen Klasse zugreifen > will. Genau. > Singleton ginge wäre aber wohl zweckentfremdet. Singleton ist das Pattern um ein Objekt einmalig zu initialisieren und wird praktisch nur im Kontext globaler Variablen benutzt. > Extern ginge auch.... aber ... unsauberer? Das wäre lediglich die zugehörige globale Variable (deren Initialisierung iwie sichergestellt werden muss). Ob Singleton/Global oder Durchreichen hängt vom Kontext ab. Häufig ist beides gleichermaßen schlecht. ;-)
Dann formulier mal die Lehrbuchlösung. Eine weitere mir eingefallene Lösung wäre entsprechende Membervariable der Klasse mit static zu declarieren. Jede Instanz dieser Klasse kann dann auf die statische Membervariable zugreifen.
Ich würde keinen Singleton verwenden. Das Pattern hat zu viele Nachteile und ist auch aus der Mode gekommen. Auch keine sonstigen technischen Spielereien. Die sauberste Lösung meiner Meinung nach wäre das injecten des "globalen" Objektes in die Objekte hinein, die das verwenden wollen. Und das nur unter Verwendung eines Interfaces. So werden Abhängigkeiten minimiert. Allerdings solltest du deine Klassenstruktur überdenken. Wenn es viele Klassen gibt, die auf das Objekt zugreifen wollen/müssen, stimmt was nicht. merciless
Die Klasse soll einen 1ms Timer counter bereitstellen. Jedes andere Klassenobjekt, das nur alle x Zeiteinheiten was machen soll, soll auf diese Timer Klasse zugreifen können. Die Timer Klasse wird mittels Observer Pattern jede 1ms im Isr kontext upgedatet und zählt in einer TimerCount Klasse eine statische Membervariable hoch. Jedes andere Objekt, das eine Zeitinformation braucht, instanziiert die TimerCount Klasse und hat Zeitinformationen. Da war meine Überlegung eben, wie diese Zeitinformation anderen Objekten zugänglich machen.
Janosch schrieb: > Jedes andere Objekt, das eine Zeitinformation braucht, instanziiert die > TimerCount Klasse und hat Zeitinformationen.
1 | struct Timer { |
2 | // start, stop, usw. usf.
|
3 | };
|
4 | |
5 | struct UseTimer{ |
6 | // tim.start, tim.stop, usw. usf.
|
7 | private:
|
8 | Timer tim; |
9 | };
|
Genau dafür solls doch Timer Objekte geben, die man in anderen Klassen nutzen kann? Da braucht man weder was durchreichen noch an Singleton usw.
:
Bearbeitet durch User
Fragen die einzelnen Klassen die "Uhrzeit" ab und entscheiden, ob sie was machen sollen weil z.B. 100ms vergangen sind? Wenn dem so ist, dann würde ich da eher eine Scheduler-Klasse schreiben, die diese Aufgabe übernimmt. Und ein Objekt instantiieren, um an eine statische Info zu kommen klingt mir overdosed: dafür gibt es public static Methoden. merciless
Janosch schrieb: > Dann formulier mal die Lehrbuchlösung. Du hattest das Für und Wider bereits geschrieben. :-) Wenn du ein bisschen im Netz schaust, wirst du zum Thema einiges an Diskussion finden. Das Durchreichen ist die "bessere" Lösung. Man kann an den Funktionsköpfen bereits sehen, welche Parameter verwendet werden. Die Kunst besteht darin, lange Parameterlisten zu vermeiden. Ansonsten wird der Code schnell unverständlich. Hast du bereits ein Projekt, wo das Durchreichen quasi ein Refactoring/Redesign erfordert, dann greifst du eher zum globalen Zugriff. Das macht den Code schwerer durchschaubar, da es "versteckte" Parameter gibt. Dokumentation ist angesagt. (Ich habe hier so ein historisch gewachsenes Projekt, wo es so viele Singletons und globale Kontexte gibt, dass man absolut im Wald steht.) Ist es dein eigenes Projekt, mach' es wie es für dich am "einfachsten" ist. Die Lehrbuchlösung gibt es leider nicht.
Mikro 7. schrieb: > Das Durchreichen ist die "bessere" Lösung. Bei der Aufgabenstellung scheint es sich um ein Art Hardwarezugriff zu handeln (für den Timer gilt „es darf nur einen geben“). Da ist eine dann globale und/oder statische Instanz doch eine sinnvolle Lösung. Oliver
Oliver S. schrieb: > Mikro 7. schrieb: >> Das Durchreichen ist die "bessere" Lösung. > > Bei der Aufgabenstellung scheint es sich um ein Art Hardwarezugriff zu > handeln (für den Timer gilt „es darf nur einen geben“). Da ist eine dann > globale und/oder statische Instanz doch eine sinnvolle Lösung. > > Oliver Für die Abstraktion des Hardwaretimers schon, aber nicht für den 1ms Observerpattern Timer, der ist nicht einzigartig. Was passiert z.B. wenn man einige der Funktionalitäten, die aktuell den 1ms Timer nutzen, auf 0.24ms umstellen muss?
mh schrieb: > Für die Abstraktion des Hardwaretimers schon, aber nicht für den 1ms > Observerpattern Timer, der ist nicht einzigartig. Was passiert z.B. wenn > man einige der Funktionalitäten, die aktuell den 1ms Timer nutzen, auf > 0.24ms umstellen muss? Das seh ich auch so. Meine Vorschlag wäre daher sowas:
1 | // Managed echte Hardware, schreibt Register, erhält Interrupt, usw.
|
2 | template<typename Registers> |
3 | struct HwTimer{ |
4 | static void init() {} |
5 | static void run() {} |
6 | static void stop() {} |
7 | };
|
8 | |
9 | // Logik fürs anmelden hier rein
|
10 | struct Timer{ |
11 | Timer(std::function<void()> callback) {} |
12 | void run(size_t ms) {} |
13 | private:
|
14 | static inline HwTimer hw_tim; |
15 | std::function<void()> callback; |
16 | };
|
17 | |
18 | // Timer Instanzen nach Lust und Laune nutzen
|
19 | struct UseTimer{ |
20 | ...
|
21 | private:
|
22 | Timer tim; |
23 | };
|
Dirk K. schrieb: > Allerdings solltest du deine Klassenstruktur überdenken. > Wenn es viele Klassen gibt, die auf das Objekt zugreifen > wollen/müssen, stimmt was nicht. Huh? Bestes Beispiel: ein Logger. Wird überall im Programm benötigt, es soll aber natürlich nur eine Instanz geben. Ist doch das Normalste der Welt :-) Ein guter Ansatz ist, shared Pointer auf die Instanz herumzureichen. Nur so kann jede Klasse mit UnitTests versehen werden. Falls das zu viel Aufwand ist: dafür gibt es Dependancy Injection Frameworks. Die nehmen einem die Arbeit ab ;-)
Quixy schrieb: > Dirk K. schrieb: >> Allerdings solltest du deine Klassenstruktur überdenken. >> Wenn es viele Klassen gibt, die auf das Objekt zugreifen >> wollen/müssen, stimmt was nicht. > > Huh? Bestes Beispiel: ein Logger. Wird überall im Programm benötigt, es > soll aber natürlich nur eine Instanz geben. > Ist doch das Normalste der Welt :-) > > > Ein guter Ansatz ist, shared Pointer auf die Instanz herumzureichen. Nur > so kann jede Klasse mit UnitTests versehen werden. Falls das zu viel > Aufwand ist: dafür gibt es Dependancy Injection Frameworks. Die nehmen > einem die Arbeit ab ;-) Ja, das ist dann genau die Ausnahme, die die Regel bestätigt ;) Ich hatte eher einen Timer im Sinn, den Zugriff auf Hardware oder ähnliches. Und man braucht nicht gleich ein DI-Framework. In meinen Applikationen mache ich das von Hand. Die Objekte werden in einer Klasse erzeugt und Abhängigkeiten injiziert. So kann ich das an zentraler Stelle ändern (für Tests etc). merciless
Injiziert heißt in dem Fall schlicht, die Objektinstanz per Konstruktor oder Methode zu übergeben oder nicht? Damit wäre es doch das "einfache" Durchreichen per Zeiger?
Jan schrieb: > Injiziert heißt in dem Fall schlicht, die Objektinstanz per Konstruktor > oder Methode zu übergeben oder nicht? Damit wäre es doch das "einfache" > Durchreichen per Zeiger? Ja, technisch nichts anderes, als einen Pointer in das Objekt reinzureichen. merciless
Quixy schrieb: > ein Logger. Wird überall im Programm benötigt, es > soll aber natürlich nur eine Instanz geben. Welche Instanz? Da hat man ne Log Funktion, fertig. Eventuell auch ein Macro, um noch die Zeile, Spalte, Funktionsname, etc. mitzugeben.
DPA schrieb: > Quixy schrieb: >> ein Logger. Wird überall im Programm benötigt, es >> soll aber natürlich nur eine Instanz geben. > > Welche Instanz? Da hat man ne Log Funktion, fertig. Eventuell auch ein > Macro, um noch die Zeile, Spalte, Funktionsname, etc. mitzugeben. In einer funktionalen Welt ja, in einer objektorientierten hat man eine Instanz. merciless
Dirk K. schrieb: > In einer funktionalen Welt ja, in einer > objektorientierten hat man eine Instanz. Es gibt ja rein theoretisch auch die Möglichkeit, ein bisschen pragmatisch nachzudenken und nicht blind einem Pattern nachzulaufen ...
Sven B. schrieb: > Dirk K. schrieb: >> In einer funktionalen Welt ja, in einer >> objektorientierten hat man eine Instanz. > > Es gibt ja rein theoretisch auch die Möglichkeit, ein bisschen > pragmatisch nachzudenken und nicht blind einem Pattern nachzulaufen ... Jo, ich bin auch Pragmatiker. Der TO hatte aber nach einer guten Lösung gefragt, nicht nach einer pragmatischen. Overengineering ist eh eines der größten Probleme beim Entwerfen von Software-Architekturen. merciless
Sven B. schrieb: > Es gibt ja rein theoretisch auch die Möglichkeit, ein bisschen > pragmatisch nachzudenken und nicht blind einem Pattern nachzulaufen ... So ein Logger braucht nun mal eine ganze Menge an Daten: - File Handles (wenn er in dateien Loggt) - Netzwerkverbindungen (wenn er auf einem Server loggt) - Thread-Handles (da das Logging vorzugsweise in einem abgekoppelten Thread laufen soll) - Queues für die Logbotschaften - Timer für das Zeitstempeln der Botschaften - Etc. Das lässt sich wunderbar in einer Klasse kapseln. Warum sollte man sowas nicht OOP lösen wollen?
Wenn man das braucht, kann man das natürlich machen. Die meisten Menschen wollen einfach nur ein paar Zeilen Text nach stdout schreiben. Dazu braucht man keine Klasse.
Quixy schrieb: > So ein Logger braucht nun mal eine ganze Menge an Daten: > - File Handles (wenn er in dateien Loggt) > - Netzwerkverbindungen (wenn er auf einem Server loggt) > - Thread-Handles (da das Logging vorzugsweise in einem abgekoppelten > Thread laufen soll) > - Queues für die Logbotschaften > - Timer für das Zeitstempeln der Botschaften > - Etc. Nein, ein Logger muss nur 3 dinge können: /dev/log unix socket öffnen, eine rfc5424 (wenn man structured data braucht) oder rfc3164 konforme Logmeldung zusammensetzen, und dann mit send die Logmeldung wegschreiben. Fertig. Filtern, übers Netzwerk, in Dateien schreiben, etc. erledigt der Systemlogger. Für rfc3164 gibts sogar eine Standard Funktion dafür: syslog(3). Ernsthaft, es gibt nichts nervigeres als sich mit den Logs solcher abnormalen Programme Herumschlagen zu müssen und aufzuräumen, die meinen, sie könnten das besser selbst und anders lösen. Selbst nach stdout loggen und durch logger pipen ist besser als was man sonst so für mist in den "professionellen" Programmen sieht.
DPA schrieb: > Nein, ein Logger muss nur 3 dinge können: /dev/log unix socket öffnen Sicher, dass das auch auf Windows, MacOS und Android funkioniert?
DPA schrieb: > Nein, ein Logger muss nur 3 dinge können: /dev/log unix socket öffnen, Das mag für deine 200-Zeilen-Pickel-Nerd-Linux-Progrämmchen gelten, aber es gibt Bereiche im echten Leben, die haben höhere Anforderungen z. B. Medizingeräte und deren Anwendungssoftware.
Quixy schrieb: > DPA schrieb: >> Nein, ein Logger muss nur 3 dinge können: /dev/log unix socket öffnen > > Sicher, dass das auch auf Windows, MacOS und Android funkioniert? Auf MAX OS X ist es glaub ich /var/run/syslog, auf BSD und anderen unixoiden wurde es teils nach /var/run/log verschoben. Muss man halt mit stat die 3 Dateien testen, bis man eine gefunden hat. Und bei Windows und Android macht man halt entweder ein ifdef und reicht die Daten der Logfunktion an die Systemnative weiter, oder linkt einfach eine alternative Implementation der Funktion für die Platform, genauso wie man das bei allen anderen Systemspezifischen Sachen auch macht. Vermutlich lassen sich auch dafür irgendwo schon fertige logging libraries finden, wenn man das Rad nicht unbedingt neu erfinden will.
Professioneller schrieb: > DPA schrieb: >> Nein, ein Logger muss nur 3 dinge können: /dev/log unix socket öffnen, > > Das mag für deine 200-Zeilen-Pickel-Nerd-Linux-Progrämmchen gelten, aber > es gibt Bereiche im echten Leben, die haben höhere Anforderungen z. B. > Medizingeräte und deren Anwendungssoftware. Wie gesagt, syslog ist ein standard, genau wie die syslog Funktion. Gerade in diesen Umgebungen sollte man sie nutzen, statt selbst was über kompliziertes zu stricken. Kliniken haben in der regel auch eine IT-Infrastruktur mit Syslog Server, zumindest wird das in manchen PDFs erwähnt, wenn man "Medizin Syslog" googelt. Wobei, spezialisierte Medizingeräte haben vermutlich ein komplett anderes System als anderes zeug, und wenn dort überhaupt was geloggt wird, dann in der regel keine Daten um das Programm zu analysieren, sondern Patientendaten, wann es sich einschalten und auf irgendwelches zeug reagieren musste, und solches zeug, also keine Logmeldungen in dem sinne, und damit auch nicht mit normalem logging in anderen bereichen vergleichbar. In diesen Geräten wird man im Hauptprogramm wohl auch keine spezielle Logger Klasse finden, vermutlich gar keine Klassen. Ironischerweise sind die Systeme oft trotzdem, oder gerade deshalb, oft weniger sicher als sonstige, normale Systeme. Dafür laufen keine dafür aber wohl keine Logfiles voll.
DPA schrieb: > und wenn dort überhaupt was geloggt wird, dann in der regel keine > Daten um das Programm zu analysieren Natürlich, unter anderem genau dafür loggt man, um nachzuvollziehen was im Feld passiert ist. Ich habe das Beispiel Medizin gebracht, weil ich selbst seit >20 Jahren Software für Computertomographen schreibe. Früher C++/MFC, heute C#/.NET (unter Windows 10 :P)
Professioneller schrieb: > Früher C++/MFC, heute C#/.NET > (unter Windows 10 :P) OMG, Ich wünschte ich müsste nicht alle Krankenhäuser meiden, wenn ich dem entkommen wollte.
DPA schrieb: > Professioneller schrieb: >> Früher C++/MFC, heute C#/.NET >> (unter Windows 10 :P) > > OMG, Ich wünschte ich müsste nicht alle Krankenhäuser meiden, wenn ich > dem entkommen wollte. Ich sehe ein Weltbild einstürzen, ...
Professioneller schrieb: > DPA schrieb: >> und wenn dort überhaupt was geloggt wird, dann in der regel keine >> Daten um das Programm zu analysieren > > Natürlich, unter anderem genau dafür loggt man, um nachzuvollziehen was > im Feld passiert ist. > Ich habe das Beispiel Medizin gebracht, weil ich selbst seit >20 Jahren > Software für Computertomographen schreibe. Nicht aus dem Kontext reissen: DPA schrieb: > Wobei, spezialisierte > Medizingeräte haben vermutlich ein komplett anderes System als anderes > zeug, und wenn dort überhaupt was geloggt wird, dann in der regel keine > Daten um das Programm zu analysieren Mit "spezialisierte Medizingeräte" meine ich Herzschrittmacher, Blutreinigungsgeräte, und solche speziellen Geräte. Software für normale PCs bei weniger direkt lebensgefährlichen Systemen würde ich eher wie die restlichen PCs in dem Umfeld betrachten, ob das jetzt in einem Computertomographen steckt oder nicht. Das sind komplett andere arten von Systemen. Professioneller schrieb: >> OMG, Ich wünschte ich müsste nicht alle Krankenhäuser meiden, wenn ich >> dem entkommen wollte. > > Ich sehe ein Weltbild einstürzen, ... Keine angst, das da etwas zu viele Windowssysteme in Krankenhäusern herumstehen war mir schon klar. man liest ja auch immer mal wieder, wenn die IT dort mal wieder vergisst die Updates oder ein mit der Spezialsoftware inkompatibles Antivirusprogramm auszuschalten, und ne OP dann deshalb abgebrochen werden muss, usw. Und dann gabs ja auch mal noch die durch WannaCry lahmgelegten Krankenhäuser...
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.