Using and Abusing the Observer Pattern
Most of the problems that come up in using the Observer pattern revolve around the frequency and timing of the updates. Sometimes the sheer volume of updates can be a problem. For example, an observer might register with a subject, unaware that the subject is going to spew out thousands of updates each second. The subject class can help with all of this by avoiding broadcasting redundant updates. Just because someone updates an object, it does not mean that anything really changed. Remember the salary= method on the Employee object? We probably should not notify the observers if nothing has actually changed:
def salary=(new_salary) old_salary = @salary @salary = new_salary if old_salary != new_salary changed notify_observers(self) end end
Another potential problem lies in the consistency of the subject as it informs its observers of changes. Imagine we enhance our employee example a bit so that it informs its observers of changes in an employee's title as well as his or her salary:
def title=(new_title) old_title = @title @title = new_title if old_title != new_title changed = true notify_observers(self) end end
Now imagine that Fred gets a big promotion and a big raise to go along with it. We might code that as follows:
fred = Employee.new("Fred", "Crane Operator", 30000) fred.salary = 1000000 # Warning! Inconsistent state here! fred.title = 'Vice President of Sales'
The trouble with this approach is that because he receives his raise before his new title takes effect, Fred will briefly be the highest-paid crane operator in the world. This would not matter, except that all of our observers are listening and experiencing that inconsistent state. You can deal with this problem by not informing the observers until a consistent set of changes is complete:
# Don't inform the observers just yet fred.salary = 1000000 fred.title = 'Vice President of Sales' # Now inform the observers! fred.changes_complete
One final thing to look out for is badly behaved observers. Although we have used the analogy of the subject delivering news to its observer, we are really talking about one object calling a method on another object. What happens if you update an observer with the news that Fred has gotten a raise, and that observer responds by raising an exception? Do you simply log the exception and soldier on, or do you do something more drastic? There is no standard answer: It really depends on your specific application and the amount of confidence you have in your observers.