user2088639
user2088639

Reputation:

Observer Pattern: Avoiding bad re-entrant behavior?

In practice, how do implementations of the Observer pattern avoid bad behavior due to reentrancy?

To clarify "bad behavior", consider the situation where a Subject in the pattern has methods MethodA() and MethodB(), events OnMethodA() and OnMethodB(), and one or more Observers, in a single-threaded, synchronous implementation:

At this point, we're calling OnMethodB() for all observers, even though we're still in the middle of the notifications for OnMethodA(). This means any observer after Observer1 in the list is going to see "OnMethodB()" before "OnMethodA()" - that's bad behavior.

Now you're going to overflow the stack. That's bad behavior.

If you've designed with asynchronous, queue-based notifications from the start, or throw exceptions on calls to Subject during notifications, you can avoid this, and that's fairly easy to understand. What's bothering me is I almost never see this mentioned as a best (or really, only) practice in implementing the pattern. You'd have to already have an awareness of the problem to google "observer pattern reentrant", and the results in that search seem to only be people who have encountered the problem, rather than warnings in a book on patterns.

So am I missing something? In practice, how do implementations of the Observer pattern avoid bad behavior due to reentrancy?

Upvotes: 5

Views: 674

Answers (3)

Simon G
Simon G

Reputation: 36

This question, about infinite recursion, is an important issue to be aware of with the observer pattern and in turn using the model view controller (MVC) pattern in a GUI application. In earlier work, I tried using the method of using flags to prevent this, but I found that using flags added complexity and would sometimes not work as expected.

The solution which I found to work for me and have been using for over five years with confidence is to break the cycle in the controller by making sure that when your code updates the state of a view, in response to a model change event, that you are not observing the events which get generated by changing the view. If that is not possible in your situation, then using a flag is your best bet.

A simple example would be a model with a single string for its data, a text field for the view and a controller object between them. If the user modifies the string, this notifies the controller which tells the model to update its string. The model change notifies the controller which updates the text field. This is where you have to be careful. The controller needs to be able to distinguish between an event from a view generated due to the user actions or its own updating of the view's content. In some cases you will be able to simply select appropriate events from the view to listen to, in other cases you will need to have the controller keep track of if it is modifying the view or not.

In this specific example, the solution is to have the controller listen for the event from the text field when it is done being edited, rather than when the text in the text field is modified.

Upvotes: 0

user949300
user949300

Reputation: 15729

As for avoiding reentrancy, one "fix" is to set a flag isResponding, isUpdating, whatever. Check on it to avoid reentrancy. p.s. make it volatile.

I am not claiming this as an elegant or even a good solution. But sometimes it's a way to go.

Upvotes: 1

Ibrahim Najjar
Ibrahim Najjar

Reputation: 19423

Well i have never heard of this issue with the Observable pattern before so +1 for that. On the other hand why don't you look at how Java has implemented this pattern in the java.util package via Observer and Observable, another note is that this problem would occur in real world applications because of improper usage of this pattern, check out these Gotchas from Martin Fowler on the Observer pattern.

Upvotes: 0

Related Questions