2016-06-03 10 views
0

Ich habe eine Situation, wenn ich einen Beobachter habe, um auch ein Thema sein. Also lassen Sie uns Bild mit haben zwei entities A und B. Wenn Änderungen in A-Modell auftreten, sollten andere entitys einschließlich B (C, D ... Etc) wissen.Observer Muster Endlosschleife

Wenn Änderungen in B's Model auftreten, sollten andere Entitäten wissen, einschließlich A (C, D ... Etc).

von implmenting das Beobachter-Muster auf diese Weise i eine Endlosschleife betteween A bekommen und B.

Ist der Beobachter pattren nicht implmented richtig oder muss ich eine andere pattren diese Art von Design behandeln?

Jede Art und Weise sie meine Implementierung

public interface ISubject { 
    public void registreObserver(IObserver obs); 

    public void removeObserver(IObserver obs); 

    public void notifyObservers(); 
} 

und die Beobachter-Schnittstelle

public interface IObserver { 
    public void update(ISubject subject); 
} 

Das Modell

import java.util.ArrayList; 
import java.util.List; 


public class AModel implements ISubject { 

    private List<IObserver> listObservers = new ArrayList<>(); 
    @Override 
    public void registreObserver(IObserver obs) { 
     listObservers.add(obs); 
    } 

    @Override 
    public void removeObserver(IObserver obs) { 
     listObservers.remove(obs); 
    } 

    public void loadData(){ 
     notifyObservers(); 
    } 

    @Override 
    public void notifyObservers() { 
     for (IObserver obv : listObservers) { 
      obv.update(AModel.this); 
     } 
    } 
} 

BModel

Import java.util.ArrayList; importieren java.util.List;

public class BModel implements ISubject { 

    private List<IObserver> listObservers = new ArrayList<>(); 
    @Override 
    public void registreObserver(IObserver obs) { 
     listObservers.add(obs); 
    } 

    @Override 
    public void removeObserver(IObserver obs) { 
     listObservers.remove(obs); 
    } 

    public void loadData(){ 
     notifyObservers(); 
    } 


    @Override 
    public void notifyObservers() { 
     for (IObserver obv : listObservers) { 
      obv.update(BModel.this); 
     } 
    } 
} 

Der A-Controller

public class AController implements IObserver { 

private AModel model; 

public void setModel(AModel model) { 
    this.model = model; 
} 

    @Override 
    public void update(ISubject subject) { 
     System.out.println(" A Changed"); 
     model.loadData(); 
    } 
} 

Die B-Controller

public class BController implements IObserver { 

private BModel model; 

public void setModel(BModel model) { 
    this.model = model; 
} 
    @Override 
    public void update(ISubject subject) { 
     System.out.println(" B Changed"); 
model.loadData(); 
    } 
} 

Hauptprogramm

public class Main { 

    public static void main(String[] args) { 
     AModel aModel = new AModel(); 
     AModel bModel = new BModel(); 

     AController aController = new AController(); 
     aController.setModel(aModel); 

     AController bController = new BController(); 
     bController.setModel(bModel); 

     aModel.registreObserver(bController); 
     bModel.registreObserver(aController); 

     // Here the updates starts a notify b and b notify a and so on 
     aModel.notifyObservers(); 

    } 
} 
+0

Dieses Codebeispiel erstellt keine Endlosschleife (wenn Sie alle Syntaxfehler beheben). Es druckt nur "B geändert" und beendet. – explv

+0

Ich habe es versäumt, Daten in das Modell zu laden, jetzt erstellt es eine Endlosschleife und ich möchte entweder die Schleife vermeiden oder das Muster ändern, um ein geeigneteres zu verwenden. –

+1

Warum implementieren Sie das Muster selbst, d. H. Erstellen Sie Ihre eigenen Schnittstellen und so? Die für dieses Muster benötigten Interfaces und Klassen sind bereits in Java implementiert, nämlich die Klasse "Observable" (Objekt, das beobachtet wird, trotz seines Namens ist es eine Klasse) und die Schnittstelle "Observer". –

Antwort

1

Der Grund, warum Sie eine Endlosschleife bekommen ist man da jedes Mal, Aktualisieren Sie Ihr Observabl e, Sie benachrichtigen seine Beobachter, aber dieser Benachrichtigungsvorgang aktualisiert das Modell erneut und wiederholt es.

Hier ist ein Beispiel dafür, wie das Beobachter-Muster in der Art und Weise, die Sie suchen verwenden:

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

public class Example { 

    public static void main(String[] args) { 

     Model modelA = new Model(); 
     Model modelB = new Model(); 

     Observer aController = (observable, arg) -> { 
      System.out.println("A controller: " + arg); 
     }; 

     Observer bController = (observable, arg) -> { 
      System.out.println("B controller: " + arg); 
     }; 

     modelA.addObserver(bController); 
     modelB.addObserver(aController); 

     modelA.update("test"); 
     modelB.update("test2"); 
    } 
} 

class Model extends Observable { 

    private String data; 

    public void update(String data) { 
     this.data = data; 
     setChanged(); 
     notifyObservers(data); 
    } 
} 

Ausgang:

B-Regler: Test

Ein Controller: test2

0

Obwohl die Antwort von @arizzle funktioniert, glaube ich, dass Sie das Observer-Muster missbrauchen.

Observer

ein Definieren einer Eins-zu-viele Abhängigkeiten zwischen Objekten, so dass, wenn ein Objektänderungen> Zustand, alle seine Familienangehörigen werden automatisch benachrichtigt und aktualisiert.

Source

Ihr Problem scheint eher wie eine many-to-many-Beziehung.In diesem Fall würde ich Ihnen empfehlen, die Mediator Pattern zu verwenden, um diese Komplexität zu verbergen.

Dies ist das kanonische UML-Diagramm für dieses Muster:

Mediator UML

Ich werde die Schnittstelle/abstrakte Klassendefinition überspringt hier Blähungen, die Antwort zu vermeiden.

Grundausführung:

class Mediator { 
    private Map<String, Colleague> participants = new HashMap<String, Colleague>(); 
    public void register(Colleague c) { 
     participants.put(c.getName(), c); 
     c.setMediator(this); 
    } 

    public void send(Colleague from, String message, String to) { 
     Colleague c = participants.get(to); 
     if (c != null && c != from) { 
      c.receive(message, from); 
     } 
    } 

    public void send(Colleague from, String message) { 
     for (Map.Entry<String, Colleague> e: participants.entrySet()) {} 
      Colleague c = e.getValue(); 
      if (c != from)) { 
       c.receive(message, from); 
      } 
     } 
    } 
} 

abstract class Colleague { 
    private Mediator mediator; 
    private String name; 

    public Colleague(String name) { 
     this.name = name; 
    } 

    public void setMediator(Mediator mediator) { 
     this.mediator = mediator; 
    } 

    public void send(String msg, String to) { 
     this.mediator.send(this, msg, to); 
    } 

    public void send(String msg) { 
     this.mediator.send(this, msg); 
    } 

    abstract public void receive(String msg, Colleague from); 
} 

class ConcreteColleague1 { 
    public void receive(String msg, String from) { 
     // do something 
     System.out.println("Received msg: " + msg + " from: " + from.getName()); 
    } 
} 

class ConcreteColleague2 { 
    public void receive(String msg, String from) { 
     // do other thing 
     System.out.println("Received msg: " + msg + " from: " + from.getName()); 
    } 
} 

es verwenden:

Mediator m = new Mediator(); 

Colleague c1 = new ConcreteColleague1('foo'); 
Colleague c2 = new ConcreteColleague2('bar'); 
Colleague c3 = new ConcreteColleague1('baz'); 

c1.send("test"); 
c2.send("test"); 
c3.send("test"); 

druckt:

"Received msg: test from: foo" 
"Received msg: test from: foo" 
"Received msg: test from: bar" 
"Received msg: test from: bar" 
"Received msg: test from: baz" 
"Received msg: test from: baz" 

Auf diese Weise, wenn Sie eine Nachricht senden, können Sie wissen, sicher th Jeder hat es erhalten, so dass Sie nicht für jeden Kollegen eine weitere Sendung senden müssen, um den neuen Staat zu kommunizieren.

+0

Ich mag die Idee, das Mediator-Muster zu verwenden, aber ich weiß immer noch nicht, wie ich die GUI-Komponenten über Änderungen im Modell informieren soll. Ich benutzte Beobachter, um Gui Components zu informieren. –

+0

Ich verstehe immer noch nicht, warum deine Modelle wissen müssen, dass sich der andere geändert hat. Ihre Modelle sollten die "Verleger" und Ihre GUI, die "Abonnenten" in dieser Situation sein. Wenn zwischen Ihrer GUI und Modellen eine 1: 1-Beziehung besteht, ist das Observer-Muster besser für Sie geeignet. So wie du es beschreibst, brauchst du vielleicht eine Mischung der beiden Muster. –

+0

Mein Problem ist, dass ich Serval-Modell jedes Modell verschiedene Ansicht benachrichtigt. Also, ich kann mich nicht sowohl von der beobachtbaren als auch von der Vermittlerklasse in meinem Modell erstrecken. Ich hoffe, das klärt ein bisschen mein Problem auf. –