0

I have an situation when i have an Observer to be a also a subject. So let's image with have two entites A and B. When Changes occurs in A's Model other entites should know including B (C,D...Etc).

When Changes occurs in B's Model other entites should know including A (C,D...Etc).

By implmenting the Observer pattern in this way i get an infinite loop betteween A and B.

Is the observer pattren not implmented correctly or do i need another pattren to handle this kind of design ?

Any way her my implementation

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

    public void removeObserver(IObserver obs);

    public void notifyObservers();
}

And the Observer Interface

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

The Model

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; import 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);
        }
    }
}

The 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();
    }
}

The 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();
    }
}

Main Program

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();

    }
}
abdou amer
  • 819
  • 2
  • 16
  • 43
  • This code example does not create an infinite loop (when you fix all the syntax errors). It just prints out "B Changed" and exits. – explv Jun 03 '16 at 14:55
  • I missed to load data to the model, now it create an infinite loop and i want to either avoid the loop or change the pattren to use a more appropriate one. – abdou amer Jun 03 '16 at 15:14
  • 1
    Why are you even implementing the pattern on your own, i.e. create your own interfaces and stuff? The interfaces and classes needed for this pattern are already implemented in java, namely the class `Observable` (object being observed, despite its name it's a class) and the interface `Observer`. – Tobias Brösamle Jun 03 '16 at 15:18
  • As per the code the load module and notifyobserver are calling each other will lead to infinite loop – Nagappa Mar 05 '20 at 05:04

2 Answers2

1

The reason why you are getting an infinite loop is because each time you update your Observable, you notify its observers, but this notifying process then updates the model again and so it repeats.

Here is an example of how to use the Observer pattern in the way you are looking for:

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);
    }
}

Output:

B controller: test

A controller: test2

explv
  • 2,709
  • 10
  • 17
1

Although @arizzle's answer works, I think you are misusing the Observer pattern.

Observer

Define a one-to-many dependency between objects so that when one object changes > state, all its dependents are notified and updated automatically.

Source

Your problem seems more like a many-to-many relationship. In this case, I'd recomend you to use the Mediator Pattern to hide this complexity.

This is the canonic UML Diagram for this pattern:

Mediator UML

I'll skip the interface/abstract class definition here to avoid bloating the answer.

Basic implementation:

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());
    }
}

Using it:

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");

Will print:

"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"

This way, when you broadcast a message, you can know for sure that everyone received it, so you don't need to make another broadcast for each colleague to communicate the new state.

Henrique Barcelos
  • 7,670
  • 1
  • 41
  • 66
  • I like the idea of using the mediator pattern, but i'm still don't know how to inform the gui components about changes in model. I was using observer to do inform Gui Components. – abdou amer Jun 04 '16 at 14:02
  • I still don't understand why your models need to know the other has changed. Your models should be the "publishers" and your GUI, the "subscribers" in this situation. If there is a 1:1 relationship between your GUI and models, the Observer pattern is better suit for you. The way you're describing it, you maybe need a mix of the two patterns. – Henrique Barcelos Jun 04 '16 at 21:36
  • My problem is that, i have serval model each model notifies diffrent view. So, i can't extend from both observeable and mediator class in my model. I hope this clarify a little bit my issue. – abdou amer Jun 05 '16 at 11:25
  • But why do you have observers that are also subjects? To me seems like your models are subjects and your views are subscribers. – Henrique Barcelos Jun 05 '16 at 18:35
  • Yes, but a view witch is(JavaFx FXML Controller) may recieve notification from diffrent models, and load data for other models ( witch make a notification to construct an infinite loop. And really i don't know what's the appropriate solution for this issue. – abdou amer Jun 05 '16 at 19:32