Registrierung von Observer

lal000r

Mitglied
Hallo zusammen,


ich habe derzeit ein kleines Problem mit der Umsetzung des Observer-Patters. Zur Zeit programmiere ich ein Schachspiel mit GUI, in welchem ich versuche das MVC-Prinzip umzusetzen.

Ein menschlicher Spieler nimmt beispielsweise Spielzüge auf der GUI des Spiels vor und Listener fungieren dabei als Controller, um die Veränderungen am model durchzuführen.
Außerdem soll es aber auch möglich sein, dass der Computer Züge durchführt, also ein Mensch gegen den Computer spielt.
Für diesen Fall hab ich mir das so gedacht, dass das Model Observable ist und die View einen Observer implementiert. Soll heißen, wenn der Computer eine Änderung am Model macht, indem er einen Spielzug durchführt, soll die View das mitbekommen und einen repaint() machen.

Ganz grob klappt das auch, allerdings mit einer Notlösung. Ich weiß nicht recht, an welcher Stelle bzw. zu welcher Zeit ich den Observer registrieren muss.

Model:
Java:
package model;
import java.util.Observable;
import controller.BoardObserver;

public class Board extends Observable {

//Variablen
//Konstruktor
//Methoden

public void executeMove(Move move) {
// führt Änderungen am Model duch, Spielzug wird ausgeführt
setChanged();
IO.println(hasChanged());
notifyObservers();

Controller:
Java:
package controller;

import model.Board;
import model.Game;
import view.BoardGraphic;

public class BoardObserver {
Game currentgame;
public BoardObserver(BoardGraphic panel) {
//Holt das aktuelle Spiel, welches durch ein Singleton-Pattern instanziiert wird	
Game currentgame = GameManager.getInstance().getCurrentGame();
		
Board model = currentgame.getBoard();
model.addObserver(panel);
//Testausgabe zur Prüfung
IO.println("neuerObserver");
	}
}

View:
Java:
package view;
import model.Board;
import model.Game;
import controller.BoardObserver;
import controller.GameManager;
import controller.Mouselistener;
import controller.MousemotionListener;
etc....

public class BoardGraphic extends JPanel implements Observer {

	private static final long serialVersionUID = 1L;
	ActivePiece activepiece = null;
	boolean isDragging, isPressed, moveExecuted = false;
	final int CELLSIZE = 80;

	public BoardGraphic() {
		this.setPreferredSize(new Dimension(650, 600));
		this.setBackground(new Color(230, 230, 250));
		this.addMouseListener(new Mouselistener(this));
		this.addMouseMotionListener(new MousemotionListener(this));
//Erzeugen des Controllers		
BoardObserver controller = new BoardObserver(this);
	}
	

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		int xStart = this.getWidth() / 2;
		int yStart = this.getHeight() / 2;
		this.setFont(g);
..........usw.

	@Override
	public void update(Observable o, Object arg) {
		IO.println("update");
		this.repaint();
	}
}

Wenn ich also nun im Konstruktor der BoardGraphic (view) den Controller erzeugen möchte und das Panel selbst übergebe, kommt es zur StackOverflow Exception. Das liegt wohl daran, dass das Game, welches mit getCurrentGame() geholt wird, zu der Zeit noch nicht besteht. (Vermute ich).

Wenn ich den Observer erst weiter unten in der paintComponent()-Methode registriere klappt das Ganze. Aber sinnvoll erscheint mir das nicht.

GameManager:
Java:
public class GameManager {


	private static GameManager gameManager = null;
	private Game currentGame;

	protected GameManager() {
		currentGame = newHumanGame();
	}

	public static GameManager getInstance() {
		if (gameManager == null) {
			gameManager = new GameManager();
		}
		return gameManager;
	}
	
	public Game getCurrentGame() {
		return currentGame;
	}

	public Game newHumanGame() {
		Player humanA = new HumanPlayer(true);
		Player humanB = new HumanPlayer(false);
		
		currentGame = new Game(humanA, humanB);
		return currentGame;
	}

	public Game newGame(Player playerA, Player playerB) {
		currentGame = new Game(playerA, playerB);
		return currentGame;
	}
// Start des Spiels
	public static void main(String[] args) {
		GameManager.getInstance();


	}
}

Game (grob):
Java:
public class Game {
	
		private Board board;
		private Referee referee;
		private GUI gui;
		private Player[] player;
		private Player currentPlayer;
		private boolean end;
		
		public Game(Player playerA, Player playerB) {
			this.board = new Board();
			this.referee = new Referee();
			this.player = new Player[2];
			this.player[0] = playerA;
			this.player[1] = playerB;
			this.currentPlayer = playerA;
			this.gui = new GUI("Spiel");
			this.end = false;
		}

Vielleicht steigt ja jemand durch meinen Code und kann mir einen Tipp geben 😉 Vielen Dank schonmal!
 
Zuletzt bearbeitet:
GameManager erzeugt ein Game, das Game erstellt eine neue GUI, die GUI braucht GameManager, welcher noch nicht initialisiert ist,
also zweiter GameManager usw.,
hättest du den StackTrace gepostet oder selber angeschaut wäre das bestimmt deutlicher zu erkennen als nur am Code

ein klassisches Problem, Lösungen auch mehr oder weniger offensichtlich, die Initialisierungsprozesse müssen auseinander gezogen werden,
der GameManager-Konstruktor und der Game-Konstruktor könnten leer sein oder zumindest auf die kompliziertesten Dinge verzichten,
bei GameManager ist es bisher nur das Game, also alles zu streichen, im Game könnte aber allein die GUI wegfallen, die ist dort bestenfalls sowieso gar nicht benötigt

dazu dann eine zentrale Stelle die alles initialisiert,
einen GameManager erzeug, ein Game, eine GUI usw.,
das Game beim GameManager einfügt, die GUI beim Game usw.

für den Moment würde es reichen nur eine Stelle aufzubrechen, GameMangager könnte ruhig wie bisher das Game erzeugen,
nur die GUI aus Game am Anfang raus, das müsste den Teufelskreis auch schon lösen
 
Danke für deine schnelle Antwort.
Ich glaube, das ist genau mein Problem. Dies ist das erstere größere Programm, welches ich in OOP schreibe. Die Fäden müssen ja alle irgendwo wieder zusammenlaufen und da hakts bei mir noch ein bisschen.
Ich wüsste jetzt nicht, wo ich die GUI erzeugen soll, wenn sie nicht im Game erzeugt wird. Hatte mir so vorgestellt, dass ich da alles zusammenbringe. Wenn du sagst, dass der GameManager bzw. das Game leer sein könnten, kann ich dir nicht ganz folgen. Irgendwo muss ich doch alles erzeugen?
Wenn ich das alles in Methoden auslagere und diese dann im Konstruktor nutze, macht das ja keinen großen Unterschied.
Oder meinst du, dass ich die Komponenten dann in der main erzeugen sollte? (Zur Info: Ich versuche nebenbei auch noch gerade den sinnvollen Einsatz von Threads zu implementieren.)

Hier mal ein kleiner Auszug des StackTrace: (Das ganze Ding würde über mehrere Seiten gehen)
Java:
Exception in thread "main" java.lang.StackOverflowError
	at sun.awt.Win32GraphicsConfig.getBounds(Native Method)
	at sun.awt.Win32GraphicsConfig.getBounds(Unknown Source)
	at java.awt.Window.init(Unknown Source)
	at java.awt.Window.<init>(Unknown Source)
	at java.awt.Frame.<init>(Unknown Source)
	at java.awt.Frame.<init>(Unknown Source)
	at javax.swing.JFrame.<init>(Unknown Source)
	at view.GUI.<init>(GUI.java:16)
	at model.Game.<init>(Game.java:27)
	at controller.GameManager.newHumanGame(GameManager.java:35)
	at controller.GameManager.<init>(GameManager.java:17)
	at controller.GameManager.getInstance(GameManager.java:22)
	at controller.BoardObserver.<init>(BoardObserver.java:13)
	at view.BoardGraphic.<init>(BoardGraphic.java:43)
	at view.MainPanel.addBoardGraphic(MainPanel.java:46)
	at view.MainPanel.<init>(MainPanel.java:24)
	at view.GUI.<init>(GUI.java:12)
	at model.Game.<init>(Game.java:27)
...............
 
nimm die main-Methode, schaffe in einem Controller eine entsprechende 'initialisiere alles'-Methode oder wo auch immer,
das sollte ja nun nicht das Problen sein,

------

einen Controller, der genau kein Observer ist, BoardObserver zu nennen, ist übrigens keine Idee, was spricht etwa gegen BoardController?
 
Eigentlich ist er ja ein Oberver, bzw. registriert ihn, oder nicht?

Hmm, dann muss ich mir sowieso nochmal grundsätzlich Gedanken machen, wo es klug wäre, alles zu erzeugen, bzw. die Threads zu starten.
 

Zurück
Oben