Mehrere Observer sollen beobachten!

munuel

Mitglied
hallo,
Ich versuch mich gerade an Modell View Control- Design bzw. an dem Observer-Pattern.
Das funktioniert so weit wunder bar wenn ich nur einen Observer angemeldet habe. Wenn ich mit zwei Arbeit aber nicht mehr.

Code:
public class Modell extends Observable  {

	private JTextArea _textArea;
	private Reader _reader;
	
	void setTextArea(JTextArea textArea ){      // Hier rauf soll mein erster Observer reagieren 
		_textArea = textArea;		
		setChanged();
		notifyObservers(_textArea);
	}
	
	void setReader (Reader reader){               // Hier soll der zweite Observer reagieren            
		_reader = reader;
		setChanged();
		notifyObservers(_reader);
	}
}

Leider ist es so das beide Observer auch bei notifyObservers reagieren egal in welcher Methode
und dann natrürlich auf ein Objekt bekommen das sie nicht verarbeiten können und sollen!

Code:
public class ObservReader implements Observer {         //2.Observer
	
	private Reader _reader;
	public ObservReader(Modell modell) {
		_reader = new StringReader("!init");
		modell.addObserver(ObservReader.this);
	}	
	public void update(Observable obs, Object v){   //Wenn er hier ein JTextArea bekommt Knalls !              		
		_reader  = (Reader) v;		
		System.out.println("Verändert Text Area");
	}	
	public Reader getReader(){
		return _reader;
	}
}

Code:
public class ViewDatei extends JInternalFrame implements Observer   //2. Observer 
{	
	....
	
	public void update (Observable obs, Object v){     // Hier knallts wenn er einen Reader bekommt
		_jTextArea  = (JTextArea) v;
		int test = _jTextArea.getLineCount();
		
		_scroller.getViewport().add(_jTextArea);		
		_content.add(_scroller);
		System.out.println("Verändert Text Area");
	}
	
}

In einem Controller wird das Modell aufgerufen um neue Werte zu bekommen:
Code:
_modell.setTextArea(_jTextArea); 
_modell.setReader(reader);

Ich weiss nicht wie ich den Oberver Objekten Klar machen soll das sie nur das eine Attribut im Modell beobachten sollen und entsprechen updaten. Weil notifyObservers( object ); unabhängig dem Argumenttyp auf beide Observer feuert. :confused:

Viele Grüsse munuel
 
Hallo ohne deine Methode notifyObservers zu kennen ist es schwer rückschluesse
auf das verhalten zuschließen...

Meine Vermutung ist die das du jedesmal alle 2 Observer updatest...

Wie wäre es mit so einer Modellklasse:?

Code:
public class Modell extends Observable  {

    private JTextArea _textArea;
    private Reader _reader;
    private Vector<Observer> observers;

    public Modell(){
        observers.add(new ViewDatei(this));
        observers.add(new ObservReader(this));
    }
    void setTextArea(JTextArea textArea ){      // Hier rauf soll mein erster Observer reagieren 
        _textArea = textArea;
        setChanged();
        notifyObserver(_textArea, 0);
    }

    void setReader (Reader reader){               // Hier soll der zweite Observer reagieren            
        _reader = reader;
        setChanged();
        notifyObserver(_reader, 1);
    }

    void notifyObserver(Object o, int index){
        if(index < 0 || index >= observers.size) return;
        observers.get(index).update(o);
    }
}

Gruß

RedWing
 
Zuletzt bearbeitet:
Hallo!

Wie wärs denn damit: ?
Wobei man sich durch das ableiten von Observable die Vererbungshierarchei verbaut... na ja, man könnte das ganze ja einfach mit Interfaces machen und dann an eine Art ObserverDelegate verwenden...
Code:
  /**
   * 
   */
  package de.tutorials;
  
  import java.util.Observable;
  import java.util.Observer;
  
  /**
   * @author Tom
   * 
   */
  public class ListenerObserverExample {
  
  	/**
  	 * @param args
  	 */
  	public static void main(String[] args) {
  
  		SomeInterestingObject interestingObject = new SomeInterestingObject();
  		interestingObject.addObserver(new Observer() {
  			public void update(Observable o, Object arg) {
 				System.out.println(o + " heinz: " + arg);
  			}
  		});
  
  		interestingObject.addObserver(new Observer() {
  			public void update(Observable o, Object arg) {
 				System.out.println(o + " fritz: " + arg);
  			}
  		});
  
  		interestingObject.foo();
  
  	}
  
  	static class SomeInterestingObject extends Observable {
  		public void foo() {
  			setChanged();
  			notifyObservers("abc");
  		}
  	}
  }

Gruss Tom
 
Thomas Darimont hat gesagt.:
Hallo!
Wobei man sich durch das ableiten von Observable die Vererbungshierarchei verbaut... na ja, man könnte das ganze ja einfach mit Interfaces machen und dann an eine Art ObserverDelegate verwenden...

Gruss Tom

Ich schwöre ja auch auf die Interface-Lösung mit irgendwelchen passenden addBliBlaBlubListener usw. Aber die Geschmäcker sind verschieden. (Und die "Lehrbücher" zeigen sowas leider nie afaik)
 
hallo ,
Danke für die eure Hilfe ,
Ich hab das Problem so gelöst das ich mir eine neue Klasse angelegt habe und diese dann als Objekt immer übergebe und von den Observern updaten lasse.
In der Klasse sind dann alle Informationen die ich brauch, ob das die beste Methode ist weiss ich nicht aber es funktioniert erst mal!

Code:
public void update(Observable obs, Object v) {     // Hier zum updaten von Reader
		cnt++;
		_dataView = (DataView) v;
                _reader = _dataView.getReader();		
	}

public void update (Observable obs, Object v){   //HIer zum updaten von JTextArea
		cnt++;
		_dataView = (DataView)v;
		_scroller.getViewport().add(_dataView.getJTextArea());		
		_content.add(_scroller);		
	}
Viele Grüsse munuel
 
Moin,
also ich halte das Konzept, diejenigen Objekte als Listener dort zu registrieren, wo relevante Änderungen auftreten, für ziemlich flexibel und sauber.
 
hallo,
Ja das kann sein ich werde noch mal alles überdenken auch die ganzen Konzepte
Mvc und Document View , GRASP - Pattern, Observer-Pattern, in vielen Büchern steht unterschiedliches !

Manche behaupten MVC ist mit Swing gar nicht durchsetzbar, weil MVC nur für Smalltalk ist
und man Document View nehmen soll.
:confused:
Andere schwören auf Modell View Controll. Und auch da gibts es verschieden Umsetzungen,
einer meint den Controller auch als Listener anzumelden der ander sagt es reicht wenn die View angemeldet ist und der Controller alles an die View meldet.
:eek:
Als Neuling ist es da erst mal schwer durchzublicken und zu erkenn was wirklich gut ist.
Ich werde deshalb versuchen verschieden weg zu probieren .
Auf Anhieb zu verstehen welcher der beste ist und vorallem auch warum , da bin ich jetzt überforder !

Viele Grüsse munuel!
 
Thomas Darimont hat gesagt.:
Hallo!

Wie wärs denn damit: ?
Wobei man sich durch das ableiten von Observable die Vererbungshierarchei verbaut... na ja, man könnte das ganze ja einfach mit Interfaces machen und dann an eine Art ObserverDelegate verwenden...

Gruss Tom

hi Tom
Hab Dein Beispiel noch mal ausprobiert. Und versucht es zu verstehen! Weil ich mit meiner Lösung eine unsauberen Weg gewählt habe. (Alle update Methoden meiner angemeldeten Observer werden aufgerufen obwohl ich nur eine davon brauche)

Aber leider ruft bei Dir die "notifyObservers" - Methode auch beide update Methoden der beiden angemeldeten Observer auf! Obwohl es doch wünschenswert wäre nur die aufzurufen die auch verlangt ist !

Ich hab Dein Beispiel noch mal ein wenig umgeschrieben:
Dabei soll beim Aufruf von" interestingObject.setFranzosen("Frankreich");" :
nur der Observer aufgerufen werden, in dessen update-Methode "Franzosen wohnen in" steht und nicht auch die update-Methode für die Italiener!

PHP:
package tom;

import java.util.Observable;
import java.util.Observer;

/**
 * @author Tom
 * 
 */

public class ObserverTom {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		SomeInterestingObject interestingObject = new SomeInterestingObject();
		interestingObject.addObserver(new Observer() {
			public void update(Observable o, Object arg) {
				System.out.println(o + " Italiener wohnen in " + arg);
			}
		});

		interestingObject.addObserver(new Observer() {
			public void update(Observable o, Object arg) {
				System.out.println(o + " Franzosen wohnen in " + arg);
			}
		});

		interestingObject.setFranzosen("Frankreich");
		System.out.println( interestingObject.countObservers());

	}

	static class SomeInterestingObject extends Observable {
		String test;
		
		public void setFranzosen(String test) {
			setChanged();
			notifyObservers(test);
		}
		
		public void setItaliener(String test) {
			setChanged();
			notifyObservers(test);
			
		}
					    
	}
}
Vielleicht habe ich aber dein Beispiel auch nicht richtig verstanden weil du auch noch Interfaces erwähntest, hast du dafür vielleicht auch noch ein Beispiel?

In meinem Lehrbuch und im Internet hab ich immer nur Beispiele gefunden bei denen es gewollt ist das bei notifyObserver alle update - Methoden der angemeldeten Objekte aufgerufen werden!
 
Hallo!

Fuer deine Zwecke eignet sich eher ein PropertyChangeListener. Damit kannst du geziehlt auf die Aenderungen eines Properties reagieren.
Java:
/**
 * 
 */
package de.tutorials;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

/**
 * @author daritho
 * 
 */
public class PropertyChangeListenerExample{

    private int data;

    private String text;

    PropertyChangeSupport propertyChangeSupport;

    public PropertyChangeListenerExample() {
        propertyChangeSupport = new PropertyChangeSupport(this);
        this.data = 1000;
        this.text="foobar";
    }

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception{
        PropertyChangeListenerExample propertyChangeListenerExample2 = new PropertyChangeListenerExample();
        
        propertyChangeListenerExample2.getPropertyChangeSupport().addPropertyChangeListener("data",new PropertyChangeListener(){
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println("Changed data: old->" + evt.getOldValue() + " new->" + evt.getNewValue());
            }
        });
        
        propertyChangeListenerExample2.getPropertyChangeSupport().addPropertyChangeListener("text",new PropertyChangeListener(){
            public void propertyChange(PropertyChangeEvent evt) {
                System.out.println("Changed text: old->" + evt.getOldValue() + " new->" + evt.getNewValue());
            }
        });
        
        propertyChangeListenerExample2.setData(4711);
        Thread.sleep(2000L);
        propertyChangeListenerExample2.setText("tutorials.de");
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        propertyChangeSupport.firePropertyChange("data",this.data,data);
        this.data = data;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        propertyChangeSupport.firePropertyChange("text",this.text,text);
        this.text = text;
    }

    public PropertyChangeSupport getPropertyChangeSupport() {
        return propertyChangeSupport;
    }
    
    
}

Gruss Tom
 
Zurück