Hallo, bin gerade dabei in C++/CLI ein kleines Spiel zu programmieren. Die vorkommenden Klassen habe ich schon im voraus erarbeitet. Da wäre die GAME_ENGINE die die Logik implementiert und Berechnungen, etc... durchführt, das USER_INTERFACE, welches die Benutzereingaben entgegennimmt und schließlich der PLAYGROUND, der die Ausgabe übernimmt. http://i.imgur.com/rDE7d.png Da der Ausgangspunkt von allem die Form1 ist, stellt sich mir die Frage wie die Struktur auszusehen hat, also die Verbindung der Klassen untereinander. Wer erzeugt wen? Wie kommunizieren die Klassen untereinander. Meine erste Idee war es, die GAME_ENGINE zu erzeugen und eine Referenz von den anderen Beiden Klassen zu übergeben (http://i.imgur.com/v12uD.png). Wie würdet ihr es machen? Danke im voraus!
Die Realisierung der Logik könnte ich mir mit Hilfe eines Zustandsautomaten vorstellen. Dieser könnte als Klasse realisiert werden, welche Methoden zur Steuerung des Ablaufs nach außen anbietet. Diese Methoden werden durch Events, die das Benutzerinterface auslöst, aufgerufen. Somit verfügt das Benutzerinterface über eine Referenz auf den Zustandsautomaten. Der Playground als Klasse bietet nach außen ebenfalls Methoden an, durch die versch. Ausgaben angestoßen werden. Dies macht der Automat, somit benötigt er eine Referenz auf den Playground. Das Benutzerinterface ist ja schon in der Form gekapselt. Man könnte entweder in der Form Instanzen von Automat und Playground erzeugen oder noch eine extra Klasse machen, die Instanzen von Form, Automat und Playground erzeugt.
wanderameise123 schrieb: > Die vorkommenden Klassen habe ich schon im voraus erarbeitet. Da wäre > die GAME_ENGINE die die Logik implementiert und Berechnungen, etc... > durchführt, das USER_INTERFACE, welches die Benutzereingaben > entgegennimmt und schließlich der PLAYGROUND, der die Ausgabe übernimmt. Aus meiner bescheidenen Erfahrung mit der Thematik: Die Strukturierung klingt furchtbar nach dem, was man in der Schule von planlosen Lehrkräften im Informatikunterricht eingeprügelt bekommt. Playground und User_Interface kannst du schlecht trennen, beides gehört zur Benutzerschittstelle. Auch ist es vermutlich Unsinn, die Benutzereingaben überhaupt noch durch eine Klasse zu würgen -- du arbeitest doch sicherlich Ereignisorientiert. Nutze die Ereignisse, die deine Umgebung dir bereitstellt, evtl. inklusive Validatoren und solcherlei. Was macht Playground dann anders, als deine Formularklasse, die du ohnehin schon instantiierst? Für die Logik -- ich kenne dein Spiel ja nicht... -- bieten sich meistens Zustandsautomaten an. Richtig interessant für OOP, so als nicht ganz realitätsnahes, aber lehrsames Beispiel, wäre es so: Jedes Lebewesen im Spiel ist ein Objekt. Und diese Objekte können selbstständig feststellen, wer um sie herum lebt... Du würdest dir dann auch automatisch Gedanken darüber machen, wer wen erzeugt und wer wen und auf welche Art wieder zerstört.
Implementiert werden soll Conways, somit wäre jede Zelle ein Objekt, und hätte eigenschaften wie tot oder lebendig und anzahl lebender nachbarn. Ok könnte man machen. Dann würde jede Zelle selbst berechnen, wie ihr nächster Zustand wäre oder? Somit bleibt die Verbindung zum user interface. Dann wäre jede Zelle auch ein grafisches Element?zB ein rectangle. Trotzdem muss eine übergeordnete instanz die elemente verwalten und zB auf die user eingaben reagieren?
Entweder Du läßt jede Zelle selbst ihren Zustand in der Folgegeneration berechnen oder Du iterierst von außen über alle Zellen und übergibst den Zellen dann den Folgezustand. Jo, Du kannst in der Klasse für eine Zelle ihre Koordinaten hinterlegen und ihr Zustand (tot oder lebendig) wird dann beim Aktualisieren der Darstellung in gefüllt/nicht gefüllt umgesetzt. Nun, wie mein Vorredner schon sagte, ist das Userinterface ereignisorientiert, d.h. es wird ein Click-, Scroll- oder Changed-Event ausgelöst und Du mußt dann im entsprechenden Eventhandler die entsprechende Aktion von Automat oder Playground anstoßen, also z.b. Neuzeichnen der Grafik oder Berechnen der Folgegeneration oder was auch immer. Eine extra Klasse brauchst Du dafür nicht, es gibt ja bereits die Form.
stimmt, aber wenn ich die form missbrauche, dann geht die modularität flöten oder? angenommen das user interface soll austauschbar sein, wäre es falsch alles in der form unterzubringen!? Zudem kann ich die arbeit so aufteilen und jeder entwickelt unabhängig, wenn man es in eine extra klasse verlagern würde. die frage ist dann nur wie die Austauschbarkeit der klassen untereinander passiert.
Deshalb hab ich ja gemeint, wenn die Instanzen von Automat und Playground an einer übergeordneten Stelle und nicht in der Form erzeugt werden, dann kannst Du das Userinterface auch austauschen, weil die Logik, die Eingabe und die Ausgabe jeweils gekapselt sind. In der Form hast Du ja normalerweise nur die Eventhandler drin, und die rufen Methoden von Automat und Playground auf. Du könntest dann den Playground zunächst als Interface definieren, das man dann auf verschiedene Art und Weise implementieren kann, z.B. als GUI-Version oder als Kommandozeilenversion.
also danke erstmal, denke das klingt alles soweit ok und logisch. Aber im moment möchte ich gerne einen anderen ansatz verfolgen und würde gerne wissen was du davon hälst:
1 | this->game = gcnew Game_Engine(); |
2 | this->playground = gcnew Playground(game); |
3 | this->user_interface = gcnew User_Interface(game); |
Ich habe die 3 klassen in der form1 instantiiert und eine Referenz der game engine an die beiden anderen klassen übergeben. So dient die game engine als austauschmodul. wäre das auch eine möglichkeit?
Grundsätzlich wäre das natürlich eine Möglichkeit, aber wie möchtest Du von der Gameengine aus den Playground steuern (für die Grafikausgabe z.B.), wenn Du in der Gameengine keine Referenz auf den Playground hast? Oder soll das von der Form aus gemacht werden?
ja das ist mir auch aufgefallen, es fehlt die referenz in die andere richtung. keine ahnung, was wäre denn sinnvoll? es würde es gerne so umsetzen, da ich es schon soweit habe.
Nun, so eine Referenz ist ja gleich übergeben ;) Du kannst es ja erstmal so lassen und es bei Bedarf dann ändern.
Vielleicht solltest du dich trotzdem von deiner Komposition (Referenzen rumreichen) lösen. Was hälst du denn davon, eine abstrakte Klasse 'Game' zu implementieren, die virtuelle Methoden besitzt, um mit dem Benutzer zu reden? Ein fertiges Spiel würde diese abstrakte Klasse dann ableiten und die virtuellen Methode vervollständigen.
Du machst dir Gedanken über Objektorientierung, das ist GUT. Dir würde jetzt folgendes helfen: http://de.wikipedia.org/wiki/GRASP Besser ist es aber hier erklärt, das Buch ist anhand seines Titelbilds schon ein Muss: http://www.amazon.de/Applying-UML-Patterns-Introduction-Object-Oriented/dp/0131489062/ Mit den GRASP-Patterns bekommst du Regeln an die Hand, mit denen du eine Lösung bzgl. lose Kopplung, hoher Zusammenhalt, Erweiterbarkeit etc. bewerten kannst. Und die Patterns sagen dir, welches Objekt etwas tuen soll.
genau das ist nämlcih das Problem. Ich erstelle Klassen, die bestimmte Dinge erledigen. Ich stelle getter/setter methoden bereit um alles nötige zu kapseln. Letztendlich fehlt mir aber das Wissen, wie ich alles in Verbindung bringe und vernetze. Ich merke wie ich trotz Klassen, alles wieder zB sequentiell mache. Irgendwie unterschätzt man das Thema!
wanderameise123 schrieb: > genau das ist nämlcih das Problem. Ich erstelle Klassen, die bestimmte > Dinge erledigen. Ich stelle getter/setter methoden bereit um alles > nötige zu kapseln. Letztendlich fehlt mir aber das Wissen, wie ich alles > in Verbindung bringe und vernetze. Falscher Ansatz Man erstellt nicht einfach Klassen, damit man Klassen hat. Man überlegt sich im Vorfeld welche Klassen man braucht, wofür eine Klasse zuständig ist, welche Aufgabe sie hat und wie alle Klassen miteinander zusammenspielen. Und erst dann gehts mit der Implementierung los. Getter und Setter sind nicht das, warum man Klassen baut. Die sind ein notwendiges Übel. Die Power einer Klasse besteht in den restlichen Memberfunktionen, welche Arbeit die verrichten können. Wenn du nur Getter und Setter hast, hättest du auch Strukturen benutzen können, das wäre kaum ein Unterschied.
Oft ist es auch einfacher, zuerst die Objekte zu analysieren, und dann daraus die Klassen abzuleiten. Ein schönes Objektdiagramm zeichnen, das hilft dir dann a) die Klassen zu identifizieren, b) Regeln und Constraints (z.B. Multiplizitäten) zu bestimmen und c) Testdaten zu haben. Übrigens besitzt eine Instanz einer Klasse nicht nur Attribute und Operationen, sondern auch eine inhärente Identität. Diese Identität siehst du genau in einem Objektdiagramm. Kauf dir wirklich das oben empfohlene Buch, da ist alles super erklärt!
Schreib dein Programm doch einfach mal konventionell, also strukturiert. Wenn du dabei das Gefühl hast, dass du was richtig Sauberes erarbeitet hast, weißt du, warum man OOP nicht braucht. Ich kenne viele Leute, die konventionell (also ganz ohne OOP) viel saubereren und leichter zu wartenden Quelltext produzieren, als andre mit OOP, Templates und was der Compiler noch so hergibt. Ist doch völlig ok. Wenn du dabei das Gefühl hast, dass alles verkorkst daherkommt, siehst du vielleicht eher, wo OOP dir das Leben erleichtert. Ich kenne auch Leute, die mit OOP die dollsten Programme konstruieren, aber völlig aufgeschmissen sind, wenns um eine blöde verkettete Liste geht, die ohne OOP geschrieben wurde (GTK...).
Karl heinz Buchegger schrieb: > Getter und Setter sind nicht das, warum man Klassen baut. Die sind ein > notwendiges Übel. Die Power einer Klasse besteht in den restlichen > Memberfunktionen, welche Arbeit die verrichten können. Wenn du nur > Getter und Setter hast, hättest du auch Strukturen benutzen können, das > wäre kaum ein Unterschied. Pfui, da mischt der alte C Hacker wieder Ansi C mit rein :-) (das ist ein Grund warum ich persönlich die Hybridsprache C++ nicht ausstehen kann, wenn man Code in die Hand kriegt ist das meist ein wüstes Gewächs aus klassischen C und Objektorientiertheit. Ich will hier keine Diskussion pro und Contra auslösen, nur mein persönliches Problem mit C++) Wenn objektorientiert dann bitte richtig, Strukturen und allein rumstehende Daten gibts nicht mehr, wohl aber Klassen die ggf. nur Daten kapseln. (z.B. ein 2 oder 3 dimensionaler Punkt) Insofern sind Getter und Setter kein notwendiges Übel. Ansonsten hast Du natürlich recht, die eigentliche Arbeit wird nicht von Getter und Setter verrichtet. Gruß :-)
U.R. Schmitt schrieb: > Pfui, da mischt der alte C Hacker wieder Ansi C mit rein :-) > (das ist ein Grund warum ich persönlich die Hybridsprache C++ nicht > ausstehen kann, wenn man Code in die Hand kriegt ist das meist ein > wüstes Gewächs aus klassischen C und Objektorientiertheit. Das ist so abwegig auch nicht. Mit BOOST hat sich das zwar geändert. Aber mit C++ alleine stehst du bei den meisten alltäglichen Aufgaben immer noch ziemlich dumm herum. Eine Datei löschen? Da sind wir wieder bei ANSI C :-)
... ... ... schrieb: > Sven P. schrieb: >> Eine Datei löschen? Da sind wir wieder bei ANSI C :-) >
1 | std::remove(foobar); |
Ja, und std::remove() ist ganz klar reinrassiges C++. So mit errno und char-Zeiger :-)
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.