Wie kann ein Observer mehrere Observables beobachten?

Silvia

Mitglied
Hallo Leute,

ich lese schon eine Weile hier im Forum sehr interessiert mit und viele Beiträge haben mir, als Java Anfänger, auch schon über einige Hürden hinweg geholfen. Jetzt komme ich an einer Stelle nicht weiter und kann auch leider dafür keine wirkliche Lösung finden. Vielleicht könnt Ihr mir ja weiterhelfen.

Zuerst einmal grundlegendes zum Projekt. Es soll einmal ein Tool zur Erstellung und Veränderung von Charakteren eines P&P Rollenspiels werden. Das heißt, ich werde einige verschiedene Klassen haben, die wiederum Werte und andere Daten verwalten und zB. Berechnungen ausführen. Angezeigt und verändert soll dies über eine Gui, in der die Daten je nach Eingabe des Users aktuell dargestellt werden. Um diese doch recht umfangreichen verschiedenen Klassen und Daten Einigermassen übersichtlich und erweiterungsfähig zu halten, möchte ich das ganze mit einem MVC Observer-Pattern realisieren.

Bei dem Observer/Observable liegt nun mein Problem. Grundsätzlich bräuchte ich dafür die Möglichkeit mit meinem/-n Observer(n) mehrere Observables zu beobachten. Leider reicht mein Können und auch mein Verständnis noch nicht ganz dafür aus. Ich kann leider kein konkretes Code Beispiel finden, das mir zeigt wie die Syntax aussehen müsste und an welcher Stelle das einzubauen wäre.

Um jetzt nicht einen riesigen Quellcode zu posten habe ich 2 Klassen mit Daten, die Gui, den Controller und die Startklasse mal in ein kleines Testprogramm gepackt und ich hoffe ihr könnt damit was anfangen. Programmiert wird mit Eclipse Helios und Java6/Swing. Bitte verhaut mich nicht gleich, ich bin noch arger Anfänger und es kann bestimmt vieles anders und besser gelöst werden. J

Java:
package silviTest;
import java.util.Observable;
/**
 * @author silvia
 *
 */
public class DatenModel extends Observable {

	private int mut; //Grundwert für Mut
	private int klugheit; // Grundwert Klugheit
	private int konst; // Grundwert Konstitution
	private int mr; // ist die Magieresistenz
	/**
	 * @return mutwert
	 */
	public int getMut() {
		return mut;
	}
	/**
	 * @param mut ist der Mut, der gesetzt wird
	 */
	public void setMut(int mut) {
		this.mut = mut;
		setChanged();
		notifyObservers(this);
	}
	public int getKlugheit() {
		return klugheit;
	}
	public void setKlugheit(int klugheit) {
		this.klugheit = klugheit;
		setChanged();
		notifyObservers(this);
	}
	public int getKonst() {
		return konst;
	}
	public void setKonst(int konst) {
		this.konst = konst;
		setChanged();
		notifyObservers(this);
	}
	public int getMr() {
		return mr;
	}
	public void setMr(int mr) {
		this.mr = mr;
		setChanged();
		notifyObservers(this);
	}
}

Java:
package silviTest;
import java.util.Observable;
/**
 * @author silvia
 *
 */
public class BasiswerteBerechnungen extends Observable {

	private int berechneMr;
	int mr_berechnet;
	/**
	 * @param mut
	 * @param klugheit
	 * @param konst
	 * @return mr
	 */
	public static int berechneMR(int mut, int klugheit, int konst) {
		int mr_berechnet = Math.round((mut + klugheit + konst) / 5);
		return mr_berechnet;
	}
	public void changeMr() {
		setBerechneMr(berechneMr);
		setChanged();
		notifyObservers(this); // eine Problemzone, ist das hier so richtig ?
	}
	public void setBerechneMr(int berechneMr) {
		this.berechneMr = berechneMr;
	}
	public int getBerechneMr() {
		return berechneMr;
	}
}

Java:
package silviTest;
import java.util.Observable;
import java.util.Observer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
 * @author silvia
 *
 */
public class TestController implements Observer {

	private DatenModel daten;
	private GraphischeOberflaeche fenster;
	private BasiswerteBerechnungen basis;
	/**
	 * initialisierung der beobachteten Klassen und Felder/Daten
	 * anhängen des observers und der Methoden,Listener
	 */
	public TestController() {
		daten = new DatenModel();
		fenster = new GraphischeOberflaeche();
		// basis = new BasiswerteBerechnungen(); // wäre das hier so richtig?
		daten.addObserver(this);
		//basis.addObserver(this);

		fenster.getMutSpinner().addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {			
				daten.setMut(((Integer) fenster.mutFeld.getValue()).intValue());
				basis.changeMr();
			}
		});
		fenster.getKlSpinner().addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {				
				daten.setKlugheit(((Integer) fenster.klugheitFeld.getValue()).intValue());
				basis.changeMr();
			}
		});
		fenster.getKonstSpinner().addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				daten.setKonst(((Integer) fenster.konstitutionFeld.getValue()).intValue());
				basis.changeMr();
			}
		});
	}
	@Override
	public void update(Observable o, Object arg1) {
		
			DatenModel model = (DatenModel) arg1;
BasiswerteBerechnungen basismodel = (BasiswerteBerechnungen) arg1; // hier bekomme ich die Fehler Exception: Kann nicht auf Basiswerte casten

			fenster.mutLbl.setText(String.valueOf(model.getMut()));
			fenster.klugheitLbl.setText(String.valueOf(model.getKlugheit()));
			fenster.konstLbl.setText(String.valueOf(model.getKonst()));

		fenster.mrLbl.setText(String.valueOf(basismodel.getBerechneMr()));
		}
}

Java:
package silviTest;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.text.JTextComponent;
/**
 * @author silvia
 *
 */
public class GraphischeOberflaeche extends JFrame implements FocusListener {
// Label zur Anzeige und Kontrolle der Daten,Berechnungen
	JLabel mutLbl = new JLabel("");
	JLabel klugheitLbl = new JLabel("");
	JLabel konstLbl = new JLabel("");
	JLabel mrLbl = new JLabel("");
	JSpinner mutFeld = new JSpinner(new SpinnerNumberModel(8, 0, 21, 1));
	JSpinner klugheitFeld = new JSpinner(new SpinnerNumberModel(8, 0, 21, 1));
	JSpinner konstitutionFeld = new JSpinner(new SpinnerNumberModel(8, 0, 21, 1));

	GridBagConstraints gbc = new GridBagConstraints();
	/**
	 * setzen der Fensterparameter
	 */
	public GraphischeOberflaeche() {

		super("Controller -> MVC Test");
		setSize(1024, 600);
		setVisible(true);

		setLayout(new GridBagLayout());
		gbc.fill = GridBagConstraints.HORIZONTAL;
		gbc.gridwidth = 1;
		gbc.anchor = GridBagConstraints.WEST;
		gbc.insets = new Insets(3, 1, 3, 1);
		setBackground(Color.yellow);

		labelHinzufuegen(mutLbl, 0, 0);
		labelHinzufuegen(klugheitLbl, 0, 1);
		labelHinzufuegen(konstLbl, 0, 2);
		labelHinzufuegen(mrLbl, 3, 2);

		spinnerHinzufuegen(mutFeld, 2, 0, "Mut");
		spinnerHinzufuegen(klugheitFeld, 2, 1, "KLugheit");
		spinnerHinzufuegen(konstitutionFeld, 2, 2, "Konstitution");

		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
	}
	/**
	 * @param label
	 * @param x
	 * @param y
	 */
	public void labelHinzufuegen(JLabel label, int x, int y) {
		gbc.gridx = x;
		gbc.gridy = y;
		add(label, gbc);
	}
	/**
	 * @param spinner
	 * @param x
	 * @param y
	 * @param tooltip
	 */
	public void spinnerHinzufuegen(JSpinner spinner, int x, int y, String tooltip) {
		gbc.gridx = x;
		gbc.gridy = y;
		add(spinner, gbc);
		spinner.setToolTipText(tooltip);
		((JSpinner.DefaultEditor) spinner.getEditor()).getTextField().addFocusListener(this);
	}
	/**
	 * @return mut
	 */
	public JSpinner getMutSpinner() {
		return mutFeld;
	}
	/**
	 * @return klugheit
	 */
	public JSpinner getKlSpinner() {
		return klugheitFeld;
	}
	/**
	 * @return konst
	 */
	public JSpinner getKonstSpinner() {
		return konstitutionFeld;
	}
	@Override
	public void focusGained(FocusEvent e) {
		if (e.getSource() instanceof JTextComponent) {
			final JTextComponent textComponent = ((JTextComponent) e.getSource());
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					textComponent.selectAll();
				}
			});
		}
	}
	@Override
	public void focusLost(FocusEvent e) {

	}
}

Java:
package silviTest;
import javax.swing.SwingUtilities;
/**
 * @author silvia
 *
 */
public class Main {

	public static void main(String[] args) {
		Runnable gui = new Runnable() {
			@Override
			public void run() {
				new TestController();
			}
		};
		SwingUtilities.invokeLater(gui);
	}
}

Anregungen, Kritik, Tipps und Hilfe sind jederzeit willkommen. Vielen Dank schon mal im vorraus an euch.
Silvia
 

Marco13

Top Contributor
Hab' jetzt nicht alles im Detail nachvollzogen, aber um den Typ zu erkennen gäbe es grundsätzlich die Möglichkeit, sowas zu machen wie
Java:
public void update(Observable o, Object arg1) 
{
    if (o instanceof DatenModel)
    {
        DatenModel model = (DatenModel)o;
        ...
    } 
    else if (o instanceof BasiswerteBerechnungen)
    {
        BasiswerteBerechnungen b = (BasiswerteBerechnungen)o;
        ...
    }
}

Ich würde dir aber empfehlen, dir deine eigenen Klassen dafür zu machen. Die Observer/Observable Klassen aus java.util sind nur eine mögliche Ausprägung dieses Musters. Sie sind zwar sehr allgemein, aber für die meisten praktischen Zwecke "ZU" allgemein (im negativen Sinne von "ZU unspezifisch" - es tritt dann eben genau das Problem auf, dass "update" aufgerufen wird, und man erstmal nicht weiß von wem und warum).

Für Anwendungen, wo man sein eigenes Datenmodell entwirft, sollte man IMHO auch einen eigenen Observer/Observable-Mechanismus implementieren, genaugenommen in Form von Listenern (und ggf. Events). Das allgemeine Muster könnte man grob so andeuten
Java:
interface Model 
{
    void setSomething(String something);
    void setSomethingElse(int somethingElse);

    void addModelListener(ModelListener modelListener);
    void removeModelListener(ModelListener modelListener);
}

// Falls es mehrere Modelle gibt, kann es praktisch sein, ein "AbstractModel" zu haben,
// wo die Listener-Verwaltung schon implementiert ist, und die anderen Methoden aus
// dem Model-Interface noch "abstract" sind:
class AbstractModel implements Model
{
    private List<ModelListener> listeners = ...

    public void addModelListener(ModelListener modelListener) { ... }
    public void removeModelListener(ModelListener modelListener) { ... }

    protected void notifyAllListenersThatSomethingChanged() { ... }
    protected void notifyAllListenersThatSomethingElseChanged() { ... }
}

// Die eigentliche Implementierung. Falls man kein AbstractModel
// hat, würden die oben genannten Methoden hier drin stehen
class DefaultModel extends AbstractModel implements Model
{
    private String s = null;

    public void setSomething(String s)
    {
        this.s = s;
        notifyAllListenersThatSomethingChanged();
    }

    ....
}


// Der Listener enthält Methoden, die in 
// 'notifyAllListenersThatSomethingChanged' aufgerufen
// werden, wenn sich am Modell etwas ändert
interface ModelListener
{
    void somethingChanged(ModelEvent event);
    void somethingElseChanged(ModelEvent event);
}

// Beschreibt eine Änderung am Modell genauer. ModelEvents
// werden in 'notifyAllListenersThatSomethingChanged' erstellt
// und an alle Listener weitergereicht
class ModelEvent { ... }

Ggf. kann man die Events auch weglassen, und den Listener einfach schreiben als
Java:
interface ModelListener
{
    void somethingChanged(String oldValue, String newValue);
}
oder so.
 

Silvia

Mitglied
Hallo,

erst einmal vielen lieben Dank Marco, für deine schnelle Hilfe.

Ich habe die vorgeschlagenene Typübergabe in die Update-Methode eingebaut und das funktioniert auch jetzt.

Java:
	public void update(Observable o, Object arg1) {
		// TODO Auto-generated method stub
		if (o instanceof DatenModel) {
			DatenModel model = (DatenModel) o;
			fenster.mutLbl.setText(String.valueOf(model.getMut()));
			fenster.klugheitLbl.setText(String.valueOf(model.getKlugheit()));
			fenster.konstLbl.setText(String.valueOf(model.getKonst()));
		} else if (o instanceof BasiswerteBerechnungen) {
			BasiswerteBerechnungen basismodel = (BasiswerteBerechnungen) o;

			fenster.mrLbl.setText(String.valueOf(basismodel.getBerechneMr()));
		}
	}
Leider tritt dadurch ein anderes Problem auf. Das Programm gibt mir zwar die Werte aus der Datenklasse aus, jedoch nicht den berechneten Wert aus der Basisberechnungen Klasse. Es sieht so aus, als wenn der else if zweig nicht bearbeitet wird. Irgendwo ist da ein Fehler drin, den ich (noch) nicht finde. Eine Exception bekomme ich nicht, der Wert wird einfach nur nicht berechnet bzw. nicht angezeigt.

Zu deinem Vorschlag mit dem eigenen Observer-Handling. Den Vorschlag finde ich sehr gut. Nur ist das für mich noch eine Stufe zu 'hoch'. Es kommt aber mit Sicherheit auf meine ToDo-Liste.

Ich lerne Java als Autodidakt und arbeite mich durch die einzelnen Programmpunkte nach dem Prinzip: erst mal muss es funktionieren, ich muss verstehen warum und dann vielleicht nach eleganteren/ besseren Lösungen suchen. :) Die Basics erarbeite ich mir dann immer zu dem aktuellen Teil. Das ist mit Sicherheit nicht die richtige oder beste Art Java zu lernen, aber so lerne ich persönlich am besten.
Daher würde mir vorerst eine funktionierende Lösung reichen, sollte das überhaupt mit dem allgemeinen Observer-Pattern möglich sein.

mit vielen Grüßen
Silvia
PS. Anregungen, Kritik, Tipps und Hilfe sind jederzeit willkommen. Vielen Dank schon mal im vorraus an euch.
 

Marco13

Top Contributor
Java:
        fenster = new GraphischeOberflaeche();
        // basis = new BasiswerteBerechnungen(); // wäre das hier so richtig?
        daten.addObserver(this);
        //basis.addObserver(this);
Wie sieht der Teil denn im Moment aus?
 

FArt

Top Contributor
Ich lerne Java als Autodidakt und arbeite mich durch die einzelnen Programmpunkte nach dem Prinzip: erst mal muss es funktionieren, ich muss verstehen warum und dann vielleicht nach eleganteren/ besseren Lösungen suchen. Die Basics erarbeite ich mir dann immer zu dem aktuellen Teil. Das ist mit Sicherheit nicht die richtige oder beste Art Java zu lernen, aber so lerne ich persönlich am besten.
Daher würde mir vorerst eine funktionierende Lösung reichen, sollte das überhaupt mit dem allgemeinen Observer-Pattern möglich sein.

Keine direkte Antwort:

Autodidakten haben es manchmal schwerer, lernen aber oft mehr.
Das Pattern ist ein Pattern, also nur ein Muster. Dazu gibt es verschiedenste Implementationen, abhängig von den Bedürfnissen. Ob für deinen Anwendungsfall ein generischer Observer eine gute Lösung ist kann ich erst mal nicht sicher beantworten. Nur ein Tipp: freunde dich mit dem Debugger an und versuche deine Fehlerfälle durchzusteppen... das Verständnis für den Code wird unheimlich wachsen.

... und ausreichend (massig) Logging einbauen am Anfang...
 

Silvia

Mitglied
Hallo Marco,

hier am besten den gesamten TestController, so wie er im moment ist.

Java:
package silviTest;
import java.util.Observable;
import java.util.Observer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
 * @author silvia
 *
 */
public class TestController implements Observer {
 
    private DatenModel daten;
    private GraphischeOberflaeche fenster;
    private BasiswerteBerechnungen basis;
    /**
     * initialisierung der beobachteten Klassen und Felder/Daten
     * anhängen des observers und der Methoden,Listener
     */
    public TestController() {
        daten = new DatenModel();
        fenster = new GraphischeOberflaeche();
        basis = new BasiswerteBerechnungen(); // hier 
        daten.addObserver(this);
        basis.addObserver(this); // und hier
 
        fenster.getMutSpinner().addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {           
                daten.setMut(((Integer) fenster.mutFeld.getValue()).intValue());
                basis.changeMr();
            }
        });
        fenster.getKlSpinner().addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {               
                daten.setKlugheit(((Integer) fenster.klugheitFeld.getValue()).intValue());
                basis.changeMr();
            }
        });
        fenster.getKonstSpinner().addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                daten.setKonst(((Integer) fenster.konstitutionFeld.getValue()).intValue());
                basis.changeMr();
            }
        });
    }
	@Override
	public void update(Observable o, Object arg1) {
		if (o instanceof DatenModel) {
			DatenModel model = (DatenModel) o;
			fenster.mutLbl.setText(String.valueOf(model.getMut()));
			fenster.klugheitLbl.setText(String.valueOf(model.getKlugheit()));
			fenster.konstLbl.setText(String.valueOf(model.getKonst()));
		} else if (o instanceof BasiswerteBerechnungen) {
			BasiswerteBerechnungen basismodel = (BasiswerteBerechnungen) o;

			fenster.mrLbl.setText(String.valueOf(basismodel.getBerechneMr()));
		}
	}
}

ich danke dir für deine Mühe und Engelsgeduld :)

viele Grüße Silvia

EDIT: vielen Dank FArt für die Anregung, werde mich gleich mal mit dem Debugger von Eclipse genauer beschäftigen, das ist ein guter Tipp. Manchmal sieht man den Wald vor lauter Bäumen nicht.

viele Grüße Silvia
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Ja, der FUrz ( :bae: ) hat schon recht: So ein paar Ausgaben wie
Java:
    @Override
    public void update(Observable o, Object arg1) {

        System.out.println("Update "+o+" arg "+arg1); //------------------------ !!!

        if (o instanceof DatenModel) {
            DatenModel model = (DatenModel) o;
            fenster.mutLbl.setText(String.valueOf(model.getMut()));
            fenster.klugheitLbl.setText(String.valueOf(model.getKlugheit()));
            fenster.konstLbl.setText(String.valueOf(model.getKonst()));
        } else if (o instanceof BasiswerteBerechnungen) {

            BasiswerteBerechnungen basismodel = (BasiswerteBerechnungen) o;

            System.out.println("*wink*");  //------------------------ !!!

            fenster.mrLbl.setText("WURDE GEÄNDERT "+String.valueOf(basismodel.getBerechneMr()));
        }
    }
zeigen schnell, dass das zwar ausgeführt wird, aber "getBerechneMr" immer 0 zurückgibt. Und wenn man sich daraufhin (!) die BasiswerteBerechnungen mal genauer ansieht, stellt man fest, das... die so irgendwie keinen Sinn macht. Die Methode "berechneMR" wird nie aufgerufen (und sollte nicht static sein!!!), und die Variable "berechneMr" erhält nie einen anderen Wert als 0.

Du solltest dir überlegen, wie die Struktur und die Abhängigkeiten dieser Klassen zueinander sein sollten - also speziell welchen Zweck "BasiswerteBerechnungen" hat. Welchen Zustand kann diese Klasse haben? Eigentlich ist sie (im Moment!) doch nur ein "Umrechner" - d.h. sie braucht im Moment keine eigenen Variablen, sondern liefert nur Ergebnisse von Berechnungen mit Werten aus dem eigentlichen DatenModel. D.h. im Moment KÖNNTE das ganze auch so sein
Java:
class BasiswerteBerechnungen // NICHT Observable
{
    private DatenModel daten;
    public BasiswerteBerechnungen(DatenModel daten)
    { 
        this.daten = daten;
    }
    public int getBerechneMR() {
        Math.round((daten.getMut() + daten.getKlugheit() + daten.getKonst) / 5);
    } 
}
(dann würde es sich aber nicht wirklich "lohnen", dafür eine eigene Klasse zu erstellen ;) )

Aber FALLS diese Klasse irgendwann noch erweitert wird, und einen eigenen Zustand hat, der NICHT vollständig durch das Datenmodell bestimmt ist, würde man da vielleicht was anderes machen....

Also: Erstmal das hier ausfüllen:
Java:
/**
 * Diese Klasse ist ... 
 * Diese Klasse macht...
 * ...
 * @author silvia
 */
class BasiswerteBerechnungen extends Observable {
...


Vielleicht noch ein bißchen ausholen: Wenn man ein Datenmodell beschreiben will, hat es Vorteile, diese in Form von Interfaces zu beschreiben. Bei der Planung/Erstellung hat es den Vorteil, dass man sich wirklich darauf konzentiert, WAS eine Klasse repräsentieren soll, und WAS die Klasse machen soll. Damit ist man quasi "gezwungen", sich auf's wesentliche zu konzentieren, nämlich die Methoden, die es irgendwann (später) mal geben wird.
Java:
interface Spieler // aka "DatenModell"
{
    int getMut();
    int getKlugheit();
    int getKonstitution();
    int getMagieResistenz();

    // set-Methoden? Vielleicht, vielleicht auch nicht... 
}
(Abgesehen davon, dass man dann schon grob sieht, ob alles funktioniert - d.h. ob compilierfehler auftreten).

Der viel wichtigere Vorteil ist aber, dass man später damit viel flexibler ist...
Java:
class Krieger implements Spieler
{
    private boolean besitztSchutzschild;
    private int mut;
    private int magieResistenz;
    ...
    public int getMut() 
    {
        if (besitztSchutzschild) return mut+10;
        else return mut;
    }
    public int getMagieResistenz()
    {
        return magieResistenz;
    }
    ...
}

Java:
class Magier implements Spieler
{
    private boolean besitztZauberstab;
    private int mut;
    private int magieResistenz;
    ...
    public int getMut() 
    {
        return mut;
    }
    public int getMagieResistenz()
    {
        if (besitztZauberstab) return magieResistenz*2;
        else return magieResistenz;
    }
    ...
(nur ein Beispiel, zur Verdeutlichung - in Wirklichkeit müßte man sich da noch mehr dazu überlegen)
 

Silvia

Mitglied
Hallo,

erst einmal Danke für die Denkanstöße und Tipps. Ich werde sie mir auf jeden Fall zu Herzen nehmen und umsetzen.

Vielleicht sollte ich die grobe Funktion meines Projekts kurz mal zusammenfassen, denn die Klassen die wir hier besprechen sind nur ein Bruchteil des ganzen endgültigen Programms.

Kurz beschrieben soll der User mittels einer Gui einen Spielcharakter entwerfen und durch beim P&P Spiel erworbene Punkte in neue Fähigkeiten investieren oder schon vorhandene Fähigkeiten ausbauen können. Dies geschieht nach einem im Spielsystem vorgegebenen Regelwerk.

Die Grundlage sind zb. die Grundwerte eines Charakters, die Herkunft, Beruf usw.
Java:
/**
 * @author silvia
 * 
 * Diese Klasse generiert die vom Regelwerk vorgebenen Minimalen Grundwerte eines Charakters mit der
 * Standarteinstellung von 8 und können über die Gui direkt und später durch die Auswahl von
 * Berufen, Herkunft, Spezialisierungen ect. zusätzlich verändert werden.//noch zu implementieren
 * 
 * Vorgegebene Werte sind Mut, Klugheit, Intuition, Charisma, Fingerfertigkeit, Gewandheit, Konstitution,
 * Körperkraft, Sozialstatus // fehlende nachtragen
 * aus diesen Werten berechnen sich weitere Werte wie Magieresistenz, Lebenspunkte, Talente ect. * 
 */
public class DatenModel extends Observable {

	// Zu Testzwecken auf Werte beschränkt die der Berechnung der Magieresistenz zugrunde liegen
	// Mut, Klugheit, Konstitution

Das ist nur ein kleiner Bereich dessen, was mein Projekt in der endgültigen Fassung beinhalten soll. Da ich wie gesagt Autodidaktisch lerne, habe ich das ganze in kleine Häppchen unterteilt und mir erst einmal nur einen Teilaspekt vorgenommen. Dieser soll allerdings, wie du schon vermutet hast, später auf weitere Klassen, Berechnungen usw. erweiterbar sein. Daher ist die Klasse BasisBerechnungen im moment wirklich nur ein Umrechner, soll später jedoch durch Modifiaktoren aus einer anderen Klasse noch zusätzlich Änderungen an den Werten vornehmen können.
Java:
/**
 * @author silvia
 * 
 * Diese Klasse ist für die Berechnungen von Werten aus dem Datenmodel und anderen Klassen //noch zu erstellen
 * zuständig und erstellt neue Werte die in der Gui angezeigt werden.
 * 
 *  Diese Klasse berechnet aus den Datenmodelwerten:
 *  Lebenspunkte, Ausdauer, Astralenergie, Magieresistenz, Kampf-Basiswerte ect. //fehlende Nachtragen
 *  
 *  // noch zu implementieren
 *  Diese Klasse soll aus den Klassen für Berufe, Herkunft ect. die Modifikatoren zur jeweiligen 
 *  Berechnung übernehmen und diese mit den Grundberechnung verarbeiten und den neuen Wert an die
 *  Gui übergeben.  *  
 */
public class BasiswerteBerechnungen extends Observable {

	// vorläufig und zu Testzwecken auf Berechnung der Magieresistenz aus dem Datenmodel beschränkt 
	// ohne weitere Klassen und Modifikatoren
	// Anzeige der berechnete Magieresistenz in der Gui für Test in Label

	private int berechneMr;
	int mr_berechnet;

	/**
	 * diese Methode soll die übergebenen Werte berechnen und bei Änderung der Daten in der
	 * Gui diese neu berechnen und dem Controller bescheid geben das und was sich geändert hat
	 * 
	 * @param mut
	 * @param klugheit
	 * @param konst
	 * @return die berechnete magieresistenz
	 */

Das ergibt dann mit Abschluß der, nennen wir es ‚Generierungsphase’, die endgültigen Startwerte eines Spielcharakters.

Später soll, unter anderem, der Charakter unter seinem Namen gespeichert, gedruckt, geladen, weiterbearbeitet werden können.

Ich habe das ganze in den Grundzügen bereits mittels einer einfachen Gui, Grunddaten, BerechnungenKlasse und eingebauten Listenern soweit hinbekommen. Der Code ist dadurch aber sehr unübersichtlich und nicht gerade Wartungs- und/oder Erweiterungsfreundlich. Daher die Idee der Trennung von Gui und Daten sowie die Nutzung von Observern. Möglicherweise bin ich aber mit diesem Ansatz auch ziemlich auf dem Holzweg.

Jedenfalls Danke noch mal für deine Hilfe und ich lese mich gerade in die Verwendung von Interfaces ein. Weitere Anregungen, Tipps ect. werden wie immer gern entgegen genommen.

mit vielen Grüßen Silvia
 
M

maki

Gast
Meine Anregung: Schon mal den PropertyChangeSupport vom JavaBeans Standard angesehen?
 

Marco13

Top Contributor
Ja, die Frage http://www.java-forum.org/allgemein...rwendet-man-propertychangedevents-eigene.html hatte ich ja auch mal gestellt... Ich tendiere eher zu eigenen, weil das unspezifische Herumreichen von Strings imho fehleranfälliger und unübersichtlicher ist...

Zum "BasiswerteBerechnungen": Dem Namen nach ist diese Klasse ja für Berechnungen zuständig, und hat erstmal eigentlich keinen eigenen Zustand. Aber wenn sie, wie angedeutet, irgendwann mal einen Zustand haben soll, der von den Eigenschaften des DatenModells (Spielers) abhängt, dann müßte sie ja selbst ein Observer des Datenmodells sein - andernfalls kann der Zustand inkonsistent werden. Und spätestens, wenn eine Klasse gleichzeitig Observer und Observable ist, wird's unübersichtlich. Ein bißchen "Vertrauen" darauf, dass das ganze am Ende funktioniert, ist wohl nicht verkehrt (nicht mit "Optimismus" zu verwechseln ;) ). Wenn man sich erstmal die ganzen Interfaces aufschreibt, und sich klar macht, wer wie mit wem zusammenhängt, wird die Struktur IMHO klarer - das entspricht von der Modellierungs-Abstraktionsstufe her ziemlich genau UML, aber ist schneller zu ändern und mit einer modernen IDE auch schnell nachzuvollziehen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
M OOP Design Pattern - "extends Observable implements Observer" Allgemeine Java-Themen 0
GreenTeaYT Verstehe nicht ganz das Observer Pattern in einer Arrayliste? Allgemeine Java-Themen 3
S OOP JFrame als Observer eines JPanel Allgemeine Java-Themen 3
A Observer und Initialisierung Allgemeine Java-Themen 7
L Registrierung von Observer Allgemeine Java-Themen 4
G 2 Observable und ein Observer... Allgemeine Java-Themen 4
M MVC: PropertyChangeListener vs Java Observer & Observable Allgemeine Java-Themen 11
Z Observer/Observable & Grundlagen Allgemeine Java-Themen 6
R Observer Umsetzungsproblem Allgemeine Java-Themen 7
K Verständnisprobleme bei Observer-Pattern mit größerem Datenmodell Allgemeine Java-Themen 32
nrg Java Observer in SysTray laufen lassen / Console schließen Allgemeine Java-Themen 2
T Observer vs Listener Allgemeine Java-Themen 18
A Observer Pattern: feuern bei neuer Referenz-Zuweisung? Allgemeine Java-Themen 8
V Threads und Observer Allgemeine Java-Themen 18
H Observer und Observable Allgemeine Java-Themen 3
U Verständnisschwierigkeiten Observer Pattern Allgemeine Java-Themen 18
B Observer vs Listener (GUI-Programmierung) Allgemeine Java-Themen 5
M Observer serialisieren Allgemeine Java-Themen 7
G Observer / Observable oder doch lieber Message Broker? Allgemeine Java-Themen 2
D Observer/Observable Pattern vs. Listener-Konzept Allgemeine Java-Themen 4
P Observer/TimerTask Allgemeine Java-Themen 3
P Observer Allgemeine Java-Themen 4
N Observer/Observable der JAVA-API od. eigene Implementierung Allgemeine Java-Themen 2
B Observer reagieren beim 2ten mal nicht Allgemeine Java-Themen 23
P Observer, nicht alle updates bearbeiten Allgemeine Java-Themen 2
P Abmelden beim Observer Allgemeine Java-Themen 4
N Observer Pattern Allgemeine Java-Themen 2
M Frage zu update Methode von Observer! Allgemeine Java-Themen 40
lhein Tutorial zu Observer / Observable? Allgemeine Java-Themen 6
G problem mit dem observer pattern Allgemeine Java-Themen 3
S Observable und Observer Allgemeine Java-Themen 10
G Frage zu (mehrfachem) Observable/Observer Allgemeine Java-Themen 2
G Frage zum Observer Pattern Allgemeine Java-Themen 4
I Mehrere Klassen mit den selben Daten Allgemeine Java-Themen 5
berserkerdq2 Ist es schlechter Programmierstyle mehrere Panes aufeinander zu machen? Allgemeine Java-Themen 1
Tarrew OpenAPI Schnittstelle - Mehrere Kunden mit unterschiedlichen Zugriffsrechten Allgemeine Java-Themen 2
A Mehrere for-Schleifen Allgemeine Java-Themen 2
M Mehrere Sounds Allgemeine Java-Themen 3
M Mehrere Ressourcen in einem package ablegen Allgemeine Java-Themen 1
Avalon DTO aus mehrere Entitäten erstellen Allgemeine Java-Themen 5
H Mehrere PNG-Files in einer Datei Allgemeine Java-Themen 9
H Mehrere Datentypen in einer Arraylist speichern Allgemeine Java-Themen 9
Curtis_MC Collections Liste anhand mehrere Kriterien sortieren Allgemeine Java-Themen 6
bueseb84 Git : Mehrere Server verwenden Allgemeine Java-Themen 3
L Mehrere .Jar Files aufrufen Allgemeine Java-Themen 9
L mehrere Methoden Allgemeine Java-Themen 19
W Variablenübergabe über mehrere Klassen Allgemeine Java-Themen 4
B StAX Parser - mehrere Methoden, ein XML Allgemeine Java-Themen 4
T String mehrere Worte Allgemeine Java-Themen 2
N Bei Mouse Events nicht mehrere Objekte erstellen Allgemeine Java-Themen 13
J Variablen Mehrere int-variablen in txt abspeichern und danach wieder auslesen Allgemeine Java-Themen 1
S JTable - mehrere ausgewählte Rows in ArrayList Allgemeine Java-Themen 5
H Java FX 2 Fragen um Programm in mehrere sprachen zu übersetzen in Gluon Framwork Allgemeine Java-Themen 3
F Listen - Mehrere Objekte Allgemeine Java-Themen 1
R Variable durch mehrere Methoden ändern und nutzen Allgemeine Java-Themen 17
S libGDX mehrere Texturen zu Einer zusammenfassen Allgemeine Java-Themen 0
X Mehrere booleans in Datei Speichern, Updaten und Laden Allgemeine Java-Themen 1
OnDemand CSV parsen mehrere Zeilen Allgemeine Java-Themen 22
K Mehrere Programmiersprachen gleichzeitig lernen Allgemeine Java-Themen 3
C Mehrere Seiten drucken in Hoch- und Querformat Allgemeine Java-Themen 0
perlenfischer1984 Mehrere Komponenten erstellen Allgemeine Java-Themen 3
F AWT Mehrere Tastatureingaben verarbeiten Allgemeine Java-Themen 5
J Mehrere Wörter getrennt in eine Array einlesen, wie ? Allgemeine Java-Themen 7
HarleyDavidson Best Practice Integer-Zahlenfolge über mehrere Programmstarts Allgemeine Java-Themen 7
F Mehrere JTables' drucken Allgemeine Java-Themen 0
2 mehrere Json Werte Parsen Allgemeine Java-Themen 3
stylegangsta Mehrere html seiten einer Homepage einlesen und als Textdatei ausgeben Allgemeine Java-Themen 14
P Mehrere Java Versionen auf dem Rechner Allgemeine Java-Themen 3
B JAVA - mehrere Clienten gleichzeitig starten. Nicht bei Code! Allgemeine Java-Themen 3
S PrintWriter.println() schreibt mehrere Zeilen Allgemeine Java-Themen 19
2 Mehrere Uhrzeiten Sortieren Allgemeine Java-Themen 2
T Jsoup: Mehrere Links nacheinander parsen Allgemeine Java-Themen 11
T Schlüsselworte mehrere public-Klassen in einem Paket Allgemeine Java-Themen 7
E Lesen von mehrere Csv-Datei und ihre Inhalte vergleichen Allgemeine Java-Themen 3
K GUI-Entwicklung - Dispose, enabling und mehrere Controller Allgemeine Java-Themen 1
M Eclipse Mehrere Threads, mehrere Konsolen Allgemeine Java-Themen 4
A Threads Lock über mehrere Abschnitte in verschiedenen Methoden Allgemeine Java-Themen 5
H Mehrere Bilder aus einer Datei lesen Allgemeine Java-Themen 2
B Mehrere Objekte verschlüsselt serialisieren Allgemeine Java-Themen 6
S Tool um mehrere Klassen in einer Klasse vereinen? Allgemeine Java-Themen 6
K Mehrere Arrays auf einmal erstellen Allgemeine Java-Themen 2
R ListIterator über mehrere Arrays Allgemeine Java-Themen 13
J JFreeChart - Mehrere X-Achsen Einteilungen Allgemeine Java-Themen 3
S Mehrere Shapes "malen" Allgemeine Java-Themen 3
M Input/Output Mehrere Bilder aus Resourcen auslesen Allgemeine Java-Themen 8
J Erste Schritte Mehrere Mauszeiger für Ping Pong Game Allgemeine Java-Themen 7
P Mehrere MP3s abspielen Allgemeine Java-Themen 3
M Mehrere CRLF entfernen Allgemeine Java-Themen 13
F Mehrere Threads - ein Stack Allgemeine Java-Themen 6
K Mehrere JVMs die auf eine Klasse mit statischen Variablen zugreift Allgemeine Java-Themen 19
B JUnit und mehrere Instanzen der selben Applikation Allgemeine Java-Themen 4
G mehrere Threads starten/stoppen Allgemeine Java-Themen 4
A Email versenden mehrere Zeilen Allgemeine Java-Themen 10
D Mehrere String-Werte in eine Tabellen-Zelle schreiben Allgemeine Java-Themen 8
R JTree - Mehrere Roots Allgemeine Java-Themen 6
Beckenbauer Mehrere Paragraphe in eine Word Datei schreiben Allgemeine Java-Themen 4
H Mehrere Anwendungen von Java kontrollieren lassen Allgemeine Java-Themen 10
T Edit: JLabel+MouseListener oeffnet mehrere Instanzen Allgemeine Java-Themen 5
O split mit einem ODER mehrere Tabulatoren oder Leerzeichen Allgemeine Java-Themen 6
M JFreeChart mehrere PieCharts erstellen Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben