Singleton hier sinnvol?

System.exit(0)

Aktives Mitglied
Hallo,

ich habe eine klasse SpielSteuerung, die sämtliche für die Steuerung des Spieles wichtigen Variablen enthält. Insbesondere die ganzen Sprites, auf die dauernd zugegriffen werden muss.
Natürlich enthält diese Klasse auch alle notwendigen Methoden.

Mit zunehmender Komplexität des Spiels ist die Klasse ziemlich lang geworden. Insbesondere da in den wichtigsten Methoden vielen ifs und switches vorkommen.

Jetzt kam mir die Idee, die notwendigen Variablen in der Klasse zu belassen und in Instanzen einer Sub_SpielSteuerung-Klasse SpielStuerung als Singleton Referenz instanziert zu haben.

Ziel ist, dass in der Mutter-SpielStuerung nur noch die Variablen zu finden sind.
Die Methoden beschränken sich hier auf die Entscheidung durch ifs udn switches, welche Unternmethode aufzurufen ist. Die genaue Implementierung der Methode - abhängig vom Spielgeschehen - geschieht dann in der Sub_Spielsteuerung.

Beispiel, wie es dann aussehen würde. drawMe ist momentan ziemlich lang - und damit unübersichtlich.

Java:
cluss Sub_SpielSteuerung()
{
     private SpielSteuerung Parent;
     
     public Sub_SpielSteuerung(SpielSteurung parent)
     {
           this.Parent = parent.getInsanceOf();
     }

    (...)

}

class Sub_Spiel extends Sub_SpielSteuerung()
{ 
(...)
}

class Sub_GameOver extends Sub_SpielSteuerung()
{ 
(...)
}

class SpielSteuerung 

private Sub_Spiel Spiel;
private Sub_GameOver GameOver;
private boolean gameisover;
(...)

public void drawMe (Graphics G)

if (gamesisover)
{
      GameOver.drawMe(G);
}
else
{
     Spiel.drawMe(G);
}
(...)

Wäre das hier ein angebrachtes Vorgehen oder sollte ich eine andere Lösung suchen.

Gruß

System.exit(0)
 
Hm wenn etwas komplex und unübersichtlich wird, dann bietet sich immer der Gedanke an, einmal über eine entsprechende Aufteilung nachzudenken.

Ich würde versuchen unterschiedliche Klassen für die einzelnen Aufgaben zu definieren.
Vielleicht sogar, dass du eine State-Machine (Zustandsautomat) baust und dort dann die vielen If/Switch dinge durch unterschiedliche Zustandsobjekte abfängst.

Für die eigentlichen Daten würde sich ein "Model" denke ich anbieten 🙂

Gruß Oli
 
Hallo,

die Aufteilung wollte ich ja über die Unterklassen machen.
Wäre denn meine SpielStuerung nicht schon fast der state-Automat?

Jede dieser Sub_Steurungen würde einen definierten Zustand des Spiels abdecken. Um einen einfachen, aber sichereren Zugriff zu gewähren, würden aber alle Spieldaten (sprich die Sprites und ein paar Umgebugnsvariablen) in der Singleton-Klasse enthalten sein.
Die Parent-Steurklasse würde dann je nach Zustand die Sub-Steurerungsklasse erzeugen, verwenden und bei einer Zustandsänderung wieder vernichten.

Das Problem, das ich habe und hier lösen will, ist eigentlich hauptsächlich die Übergabe der Sprites, die ja in der (Ur) Steuerung gespeichert sind.

Die Sub_Steuerungen sollen lediglich das Ausführen der jeweils notwendigen Logiken und das Zeichnen des jeweils zu Zeichnenden sicher stellen.

Die einzelnen Logiken für Bewegungen und Zeichnen ist in den Sprites definiert und für die Collisions, das Erzeugen und Löschen neuer Sprites gibt es ebenfalls eine Klasse, die das übernimmt.

Gruß

System.exit(0)
 
Hm Singleton geht natürlcih, aber das ist immer sehr global. Lieber den Objekten direkt das benötigte zuweisen, dann sieht man auch bei der verwendung schnell die Abhängigkeiten.

Du kannst ja für deine Zustandsobjekte eine abstrakte Oberklasse erzeugen,
die dann eine Referenz auf das Daten-Objekt hat und somit hat jeder Zustand, Zugriff auf die Daten, ganz ohne Singleton 🙂

Gruß Oli
 
Ja, das Singleton. Die Datenhure, wo jeder mal drüberrutschen darf. Und wenn man was hat, wo man nicht weiß, wo es hin soll, packt man's in's Singleton, weil das ja praktischerweise immer und überall verfügbar ist. Der Effekt, dass so eine Klasse immer länger wird, und immer mehr Dinge in sich vereint, die eigentlich nichts miteinander zu tun haben, ist wohl nicht ungewöhnlich.

Wenn ich das richtig verstanden habe, war die Hauptintention für das Singleton ja das zur Verfügung stellen der Sprites. Warum die Sprites nicht an einer dedizierten Stelle geladen und den Klassen übergeben werden, die sie brauchen, weiß ich nicht. Wenn es NUR darum geht, also das Singleton im Sinne eines ... "abstrahierten File Systems", oder eines "Sprite Repositories" verwendet wird, könnte es sogar OK sein. Aber die Spielsteuerung an sich sollte man wohl nicht in ein Singleton packen.
 
Hmm... GRUNDSATZDISKUSSION 😀
Masterkontrollstruktur (Service) -> Singleton
Spielsteuerung -> Masterkontrollstruktur
...Ich würde schon für Singleton plädieren.
 
Jippi.. ich liebe Grundsatzdiskussionen 😀

ne spaß 🙂

aber ich finde, er kann in dem Fall auch gut ohne Singleton auskommen 🙂

Ätsch .... 😉

Gruß Oli
 
@Marco13

Genau darum geht es: Die Sprites als "abstrahieretes FielSystem" (schöner Begriff).
Die Klassen, denen das Singleton übergeben würde, würden nur auf die Sprites und deren Methoden zugreifen.
Selbst das Hinzufügen oder Löschen von Sprites würde immer noch in den dafür vorgesehen Klassen passieren.

Gruß

System.exit(0)
 
???:L Ein Singleton, das noch irgendwo hin übergeben wird?

Also, dann mal ganz rudimentär: Wer sollte wann wo aus welchem Grund etwas machen wollen (oder können, oder dürfen), was mit
Spielsteuerung.getInstance(). ...
anfängt?
Gut erkannt Marco13, ein Singleton macht hier überhaupt keinen Sinn, sowas ist eine Mischform aus Resource Lookup(Singleton) & Dependency Injection, mit den Nachteilen von beiden:
Java:
     public Sub_SpielSteuerung(SpielSteurung parent)
     {
           this.Parent = parent.getInsanceOf();
     }
Dazu wird da noch das Law of Demeter verletzt...

Entweder richtiges Singleton mit klassischem Zugriff oder DI, beides für sich alleine ist immer noch besser als diese Mischform...
 
Ich habe jetzt angefangen, mein Spiel auf Singleton umzustellen.
Dabei ist die Klasse GameData das Singleton (Instanz heißt myData) und die Methoden get...() liefern die Referenz auf die Sprite-Liste.

Aber ich habe festgestelllt, dass ich mich dabei komisch fühle, weil ich letztlich alle wichtigen Variablen dadurch indirekt auf public setze.

Spricht eigentlich, abgesehen bom Tipp-Aufwand, etwas gegen solche Methoden, bei denen zig Parameter übergeben werden (manchmal auch mehr als benötigt, da die Methoden von einer abstrakten Klasse kommen, um sicher zu stellen, dass alles, was man benötigen könnte, auch da ist)?

Ich finde, dass es vielleicht den Code nicht ganz so übersichtlich macht, solch lange Methodenaufrufe, aber irgendwie fühlt es isch besse an.

Was sagt ihr?

Gruß

System.exit(0)

ohne Sinleton:
Java:
 public void DrawMe(SpielSteuerung Parent, Rakete myShip, 
                    MyListClass<MySprite> myStars, MyListClass<MySprite> myBullits, 
                    MyListClass<MySprite> myAliens, MyListClass<MySprite> myAlienBullits, 
                    MyListClass<MySprite> myExplosions, int fps, Graphics G, FontMetrics FM) 
{
       G.clearRect(0, 0, myMain.width, myMain.height);

        G.setColor(Color.white);
        // Sterne zeichnen
        if (myStars.size() > 0)
        {
        for (MySprite S : myStars)
            S.drawMe(G);
        }
(...)
}

mit Singleton:
Java:
 public void DrawMe(SpielSteuerung Parent, int fps, Graphics G, FontMetrics FM) 
{
       G.clearRect(0, 0, myMain.width, myMain.height);

        G.setColor(Color.white);
        // Sterne zeichnen
        if (myData.getmyStars().size() > 0)
        {
        for (MySprite S : myData.getmyStars())
            S.drawMe(G);
        }
(...)
}
 
Solange, gesetzt den Fall es gibt mehrere Methoden, diese dieselben Objekttypen als Parameter erwarten, kann man diese Parameter zugunsten der Übersicht auch in einer "Struktur" (Sprich einer Klasse, die nur Eigenschaften und keine Methoden hat) bündeln. Ferner könnte man auch innerhalb der Methode z.B. die FontMetrics immer wieder neu aus Graphics holen.
Zusätzlich könnte man die diversen Sprite-Listen in einer Enumeration zusammenfassen (Collection<MySprite> implementieren, zu überschreibende Methoden einfach an interne Collection delegieren). Dieser Enumeration kann man dann DrawMe als statische Methode hinzufügen. Die interne Collection könnte man ebenfalls statisch machen. Hätte den Vorteil, das man nur eine benötigt, aber dann müssten die Zugriffe (insbesondere die Iteration darüber) unbedingt synchronisiert werden, was ohnehin jetzt schon ratsam ist (bitte nicht so pauschal sehen wie es klingt).
 
Ich habe jetzt angefangen, mein Spiel auf Singleton umzustellen
....
ohne Sinleton:
Java:
 public void DrawMe(SpielSteuerung Parent, Rakete myShip, 
                    MyListClass<MySprite> myStars, MyListClass<MySprite> myBullits, 
                    MyListClass<MySprite> myAliens, MyListClass<MySprite> myAlienBullits, 
                    MyListClass<MySprite> myExplosions, int fps, Graphics G, FontMetrics FM) 
{
...

Und in welcher Klasse steht das? Könnten die Listen nicht ohnehin lokal in dieser Klasse liegen? Oder (wie schon gesagt wurde) EINE Instanz einer Klasse übergeben werden, die diese Sachen zusammenfasst?
 
Hallo,

Danke für die die Hinweise.
Mir ist jetzt nich ganz klar, wie die Klasse
(Sprich einer Klasse, die nur Eigenschaften und keine Methoden hat)
aussehen müsste. Wahrscheinlich ist es noch zu früh, ich steh gerade auf dem Schlauch.

Der Zugriff ist jetzt schon synchronisiert, oder besser gesagt, linear gestaltet. Der keyListener ist gegen den Zugriff auf eine gerade benutzte Liste über eine boolean abgesichert.

Gruß

System.exit(0)
 
Ungefähr so:
Java:
class MyStruct {
  public SpielSteuerung parent;
  public Rakete myShip;
  public MyLisstClass<MySprite>
    myStars,
    myBullits,
    myAliens,
    myAlienBullits,
    myExplosions;
  public int fps;
}
Graphics und FontMetrics hab' ich mal weggelassen, weil es alles andere als sinnvoll ist, diese dort mit einzubringen.
Das die Member nun alle [c]public[/c] sind, ist auch nicht das beste Design. Besser wäre entweder [c]public final[/c], Objekte müssten dann einmal per Konstruktor übergeben werden, oder [c]private[/c], dann müssten die Member per Getter und Setter beeinflusst werden. In der Regel kommt man sehr schnell drauf, dass man die Listen doch besser (wie Marco13 bereits sagte) mit in die Klasse übernimmt, die [c]DrawMe[/c] enthält.
Im übrigen: Ein boolean bietet äusserst wenig Schutz vor RaceConditions. Obendrein ist es meistens als eine Art Busy-Waiting einzustufen (implementierungsabhängig).
 
Ja, das Singleton. Die Datenhure, wo jeder mal drüberrutschen darf. Und wenn man was hat, wo man nicht weiß, wo es hin soll, packt man's in's Singleton, weil das ja praktischerweise immer und überall verfügbar ist. Der Effekt, dass so eine Klasse immer länger wird, und immer mehr Dinge in sich vereint, die eigentlich nichts miteinander zu tun haben, ist wohl nicht ungewöhnlich.
wie geil... fast Signaturenwertvoll 🙂
 
Hallo,

ich will meine Variablen eben icht public haben. Deswegen war ich so verwundert über die Klasse ohne Methoden.

Mit private Variablen im Singleton arbeite ich schon.

Java:
class MyStruct {
  private SpielSteuerung parent;
  private Rakete myShip;
  private MyLisstClass<MySprite> myStars

  public MyStuct (SpielSteuerung Parent)
  { this.parent = Parent;
     myShip = new myShip();
    myStars = new MyListClass <MySprite> ("myStars"); 
  public int fps;
  }

  public MyListClass <MySprite> getmyStars()
  { 
     return myStars;
  }

  public Rakete getmyShip()
  {
     return myShip;
  }
 usw.
}

Einer Setter Methode bedarf es nicht, da die Referenz übergeben wird und jede Manipulation der Liste in der Referenzadresse geschieht.

Somit liefert z. B. folgender Befehl in einer anderen Klasse das gewünschte Ergebnis, dass der Liste myStars ein Stern zugefügt wird.

Java:
(...)
    // myData wäre hier die in der Spielsteuerung erzeugt einzige Instanz von myStruct
   myData.getmyStars().add(new Stern( ... ));
    // oder festlegen der Position von myShip
   myData.getmyShip().setCoord(100, 100);

usw.

System.exit(0)
 
Spacereat's Vorschlag von "MyStruct" war wohl nur sinnbildlich - natürlich würde man da get/set Methoden für die Zugriffe verwenden.

Aber mal was ganz anderes: Was (zum ...) ist eine "MyLisstClass"? (Abgesehen davon, dass dieses "My"-Präfix IMHO :autsch: ist) Sollte das nicht einfach eine List sein?
 
Öhm... [c]MyLisstClass[/c] ist 'n Druckfehler... 😳 sollte eigentlich [c]MyListClass[/c] heissen, wie vom TS vorgeschlagen...
[c]Structs[/c] in Java? ...jibbet doch jar nich... ist natürlich nur sinnbildlich gemeint. Aber ich bin immer noch der Meinung, dass die Felder auch ruhig [c]public final[/c] sein dürfen, wenn sie sich zur Laufzeit, abgesehen vom Inhalt, ohnehin nicht ändern (ein Indiz dafür ist, das es nur Getter geben soll). Was sie hingegen nicht sein dürfen, ist [c]public[/c] only, weil dann könnte jeder ungeprüft die Daten verändern.
 
Die LIsten werden ständig geändert. Es kommen MySprites dazu, es werden welche gelöscht.
Und man benötigt auch dann nur getter, wenn man die Listen ändern will.

Probiert es aus, so wie es oben beschrieben ist. Die get-Methoden übergeben Referenzen, somit kann ich den Inhalt, der sich hinter dem Pointer befindet, ändern.

MyListClass ist abgeleitet von ArrayList, damit ich beim Aufruf des Konstruktors ein paar debug-Infos speichern kann (u.a. den String, der beim Konstruktor übergeben wird).

Gruß

System.exit(0)
 
Probiert es aus, so wie es oben beschrieben ist. Die get-Methoden übergeben Referenzen, somit kann ich den Inhalt, der sich hinter dem Pointer befindet, ändern.
Heisst das, dass die Listen innerhalb der Klasse ständig neu instanziert werden? Und das die Klassen die sich eine Instanz der aktuellen Liste holen diese dann überall verändern bzw. drüber iterieren können? Fatalerweise vllt. noch in verschiedenen Threads (z.B. EDT bzw. KeyListener) unsynchronisiert und unkopiert? Dann aber ganz schnell weg vom ewigen neu instanzieren.
Java:
class SomeClass
{
  private final List<Sprite> sprites = new ArrayList<Sprite>();

  public void addSprite(Sprite s)
  {
    synchronized(sprites) {
      sprites.add(s);
    }
  }

  public void removeSprite(Sprite s)
  {
    synchronized(sprites) {
      sprites.remove(s);
    }
  }

  public Sprite getSprite(int index)
  {
    synchronized(sprites) {
      sprites.get(index);
    }
  }

  public List<Sprite> getSprites()
  {
    synchronized(sprites) {
      return new ArrayList<Sprite>(sprites);
    }
  }
}
Über die List, welche man durch [c]getSprites()[/c] bekommt, kann an jeder Stelle im Programm gefahrlos iteriert werden. Werden während der Iteration Sprites hinzugefügt oder entfernt, wird dieses erst beim nächsten Durchlauf registriert. [c]someclass.addSprite(sprite);[/c] durfte auch um einiges bequemer sein als [c]someclass.getSprites().add(sprite);[/c]. Während ersteres von überall aus dem Programm aufgerufen werden kann, bekommt die Hauptliste beim 2. das hinzufügen von Sprites kaum (faktisch sogar gar nicht) mit.
@Edit: Nochmal zum Thema... Ich würd' sagen, das wir uns vom Singleton inzwischen doch in gänze verabschiedet haben. Für deine Klasse Spielsteuerung ist mir grad' noch folgendes eingefallen... http://www.java-forum.org/allgemein...m-design-stichwort-oo-pattern.html#post567052
 
Zuletzt bearbeitet von einem Moderator:

Zurück
Oben