design-problem
-
hallo! ich habe eine frage, was das design von einer klassenhierarchie hier betrifft, und suche vorschläge, wie man das eleganter lösen könnte (oder suche argumente, die dagegen sprechen)
ich habe zunächst mal eine abstrakte basisklasse, die bestimmte operationen zur verfügung stellt (wie z.b. operator==, ...). diese basisklasse soll die basisklasse für eine gruppe von singletons sein, die jeweils verschiedene eigenschaften darstellen. dann gibt es eine zweite hierarchie, deren kinder verschiedene konkrete dinge darstellen, wobei alle instanzen einer klasse bestimmte eigenschaften haben sollen, die von den singletons der anderen hierarchie gehalten werden (d.h. ein singleton pro abgeleiteter klasse) - dafür dachte ich, könnte man das CRT-pattern einsetzen. zusätzlich soll jede instanz der abgeleiteten klassen auch die methoden der eigenschaft-singletons anbieten.es ist geht dabei um eine (bio)chemie-simulation, ganz vereinfacht geht es darum, dass bestimmte substanzen bestimmte eigenschaften haben. beispielsweise wasser: eine bestimmte menge wasser (instanz) hat aber dennoch gewisse eigenschaften von wasser (z.b. masse, die eigenschaft wasser zu "sein" - also ähnlich RTTI). die hierarchie sieht nun so aus (als beispiel ein RTTI ähnliches konstrukt, ist in wahrheit aber komplexer, die id ist nämlich kein int, also nicht darüber aufregen!)
class Signature //Basis der ersten Hierarchie { public: virtual int get_id () = 0; virtual ~Signature() {} friend bool operator == (Signature const& a, Signature const& b) { return a.get_id() == b.get_id(); } }; template <class Substance> //quasi-singletons class CreateSignature : virtual public Signature { public: CreateSignature () { id_ = ... } private: static CreateSignature instance_; static int id_; int get_id () { return id_; } } class Substance : virtual public Signature { public: //... } class Water : public Substance, private CreateSignature<Water> { }; //... Water a(100L), b(50L); a == b //ja, beides ist wasser (mit bestimmten eigenschaften)der vorteil hier ist, dass jede konkrete substanz nur von CreateSignature erben muss, wo bestimmte allgemeine eigenschaften je klasse automatisch generiert werden (beziehung hat-eine signatur), durch das virtuelle erben wird sichergestellt, dass auf die eigenschaften, die durch createsignature automatisch erstellt werden auch konkret zugegriffen werden kann.
was ich nun aber gehört habe ist, dass sowohl virtuelle vererbung, multiple vererbung als auch private vererbung böse sind. ist das also schlechtes design?
-
Entschuldigung, aber dein Quelltext ist der pure Wahnsinn.
Du redest viel über die Implementierung. Mir kommt es aber so vor als ob du nicht weißt warum man Singletons, Templates, Vererbung, ... einsetzt. Die Implementierung passt sich dem Design an und nicht umgekehrt. Und das Design eines Programms sollte in erster Hinsicht einfach sein. Also kommt in einem Design sehr sehr selten Implementierungsdetails mit ins Spiel.
Übrigens habe ich auch keinerlei Ahnung was denn eine virtuelle Vererbung ist.Im Desgin geht man erst hin, und definiert das Problem wie du es im zweiten Absatz gemacht hat.
es ist geht dabei um eine (bio)chemie-simulation, ganz vereinfacht geht es darum, dass bestimmte substanzen bestimmte eigenschaften haben. beispielsweise wasser: eine bestimmte menge wasser (instanz) hat aber dennoch gewisse eigenschaften von wasser (z.b. masse, die eigenschaft wasser zu "sein" - also ähnlich RTTI). die hierarchie sieht nun so aus (als beispiel ein RTTI ähnliches konstrukt, ist in wahrheit aber komplexer, die id ist nämlich kein int, also nicht darüber aufregen!)
Daraus ließe sich schon der ersten Quellcode (oder UML-Klassendiagramm) generieren:
class Property { virtual int GetValue(); // liefert Wert des Typs (1m, 1 qm, ..) zurück virtual int GetType(); // liefert Typ (Einheit, Zerfallsrate, ...) zurück virtual bool operator==(Property const& a, Property const& b); } class Signature : public Property // unter der Annahme dass eine Signatur auch eine Materialeigenschaft ist { } class Substance { // Jede Substanz hat mehrere Eigenschaften Property properties[100]; unsigned int size; Signature signature; virtual bool operator==(Property const& a, Property const& b); Substance(); };Dies ist natürlich kein funktionfähiger Quelltext, aber wenn man ihn nun weiter verfeinert, kommt man sicherlich zu einem besser strukturierten Quelltext. Unter Verfeinerung verstehe ich hierbei dass die Klassen weiter ausgebaut werden und das die Klassenstruktur weiter ergänzt wird. UML-Klassendiagramme sind da oft hilfsreich. Und das würde ich dir auch mal empfehlen. Schau dir doch mal die Grundlagen zu Klassendiagrammen an. Insbesondere was Vererbung, Spezialisierung, Generalisierung starke und schwache Aggregation. Dann wirst du feststellen was du von Templates, Vererbung, ... wirklich benötigst.
Und zum Schluss der Grund warum multiple Vererbung böse sein kann. Nemen wir also mal an dass die Klassen Substance und CreateSignature eine öffentliche Integer-Variablen XYZ definiert haben und ich mittels der Klasse Water darauf zugreifen möchte. Da Water von Substance und CreateSignature erbt, existiert die Variable XYZ zwei mal und das ist nicht gut.
-
Hi,
ich schließe mich "Bit" prinzipiell an.
Noch eine prinzipielle Anmerkung: Sobald eine Klasse eine "Typ-ID" hat (und so sieht es mir bei Dir aus), sollte man dringend und gründlich Alternativen in Erwägung ziehen. Für sowas gibt's in C++ soviele schöne Alternativen, dass man sich eine "Handimplementierung" (und vA die damit verbundenen Probleme) in aller Regel sparen kann.Gruß,
Simon2.
-
Eine Sache noch:
Bitte entschuldige wenn meine Worte ein wenig hart waren. Du hast dir sicherlich einige Mühe gemacht und die einzelnen Konzepte/Techniken angeschaut. Und nun komme ich (wir) und sagen dass du nun erstmal deine Konzepte in den Hintergund stellen kannst.
Das ist ein Kernproblem der Informatik. Die Kunden geben oftmals schon Implementierungsdetails schon lange vor der eigentlichen Implementierung vor. Je nach Größe des Problems kommt nämlich erst mal eine Anforderungsanalyse (Was wird simuliert. Wie sieht die Umwelt aus ?. Soll die Simulation evt. später erweitert werden ? Was sind die möglichen Eingaben / Ausgaben der Simulation ? ...). Danach erfolgt die Design-Phase in der ein erstes objektorientiertes Modell (Klassendiagramm) aufgebaut wird. Anhand dieses Modells soll ein Nicht-Informatiker in der Lage sein, die Situation bzw. Problemstellung zu verstehen. Und danch erfolgt die Verfeinerung des Klassendiagramms. Dieses Klassendiagramm kann man dann direkt in Quellcode umwandeln. Und ganz zum Schluss wird getestet und je nach gefundenem Fehler wieder zu den einzelnen Phase gesprungen.
Und tätärätä, dies ist die einfachste Vorgehensweise aus dem Software Engineering: das Wasserfallmodell.
Wenn ich mal herausfinde, wie man Bilder in diese Forum stellen kann, würde ich dir mal ein solches Klassendiagramm zeigen.
-
Bitte ein Bit schrieb:
...
Das ist ein Kernproblem der Informatik. Die Kunden geben oftmals schon Implementierungsdetails schon lange vor der eigentlichen Implementierung vor....
Üblicherweise:- in krasser Überschätzung der eigenen Fähigkeiten ("Habe doch damals im Studium auch programmiert - weiß doch, wie' geht!") und
- weil die fachliche Definition des Problems (vor allem der Einschränkungen) oftmals schwierig ist.
Einer unserer Kunden ist schon legendär mit seiner Lieblingsantwort auf die Frage: "Wie soll das denn laufen: <xyz> oder <abc> oder was ganz Anderes ?":
"Naja, da macht man einfach ein Flag in die Schnittstelle." ...
(auf Nachbohren kommen dann "wenn/dann"-Kaskaden)
In letzter Zeit ist der Kunde aber seeeehr viel demütiger geworden, seit er mit seinem ersten "Selbstentwicklungsversuch" derbst auf die Nase gefallen ist.
(Gerechtigkeit rules!)
Gruß,
Simon2.
-
Hier noch ein kleiner Hinweis:
Übrigens habe ich auch keinerlei Ahnung was denn eine virtuelle Vererbung ist.
http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9
Gruss Simon