How to avoid infinite loop in Observer pattern?

前端 未结 5 1948
悲哀的现实
悲哀的现实 2021-01-03 02:35

I have only one class with many instances. Every instance is observer of couple of other instances. As well every instance can be observable by couple of another instances.<

相关标签:
5条回答
  • 2021-01-03 02:48

    One way is to only fire events like updated if something was actually updated. The benefit of this approach is that you can often reduce the number of events triggered (reducing work) and simplify the code. e.g.

    final Set<String> set = ...
    
    public void onAdded(String string) {
       // is only added once.
       if (set.add(string)) {
           // only notifies once no matter how many times onAdded is 
           // called for this string, recursively or not.
           notifyAdded(string);
       }
    }
    
    0 讨论(0)
  • 2021-01-03 02:54

    Let your observers add received events (or their ids) to some temporary storage and when every new event is received let them verify whether the same event is saved in the storage. If it is then they shouldn't handle it.

    But if we'll try to solve a problem rather than find a suitable workaround then: your problem is that object A can listen to object B, and object B can listen to object A at the same time (maybe with some intermediary objects). It's a bad design IMHO.

    Observers should be used to loose coupling, making object A know about object B, but not vice versa.

    If your objects A and B both know about each other then I don't see why you need to use observers.

    0 讨论(0)
  • 2021-01-03 02:57

    Well, if you are defining the "event" object, you could maybe add to it the objects that have processed the event already. In that case, if you close the loop you can exit. In seudo-code

    eventFired(Event e)
      if (e.hasBeenEvaluatedBy(this)){
        return;
      }
      e.addEvaluator(this);
    
      // Do magic
    
      refire(e);
    }
    

    In this case we get something like: * A fires something. * B processes it and adds itself to the list * B refires * C processes event and adds itself to the list * C refires * A processes the event and adds itself to the list * A refires * B catches the event, but is already on the list. No refire, infinite loop broken

    Ids could be used instead of pointers to avoid garbage collection issues

    0 讨论(0)
  • 2021-01-03 03:06

    If your system is single threaded, then you simply need a guard inside your notify method:

    private boolean _notifying;
    
    public void notify() {
      if(_notifying) {
        return;
      }
      _notifying = true;
      try {
        // ... do notifying here...
      } finally {
        _notifying = false;
      }
    }
    
    0 讨论(0)
  • 2021-01-03 03:11

    What you are looking for is a graph-traversal algorithm that detects cycles. One simple approach (that only works in a single threaded scenario) is to keep a global/static counter to let each top-level update() invocation get a unique identifier. Each observer then tracks whether already it has processed the update with the given identifier (ID) and in that case ignores it. This means that your update method will have to be expanded with a parameter with the ID number of the specific update.

    0 讨论(0)
提交回复
热议问题