I was learning a bit about about observers. Ruby has an Observable
module, but I decided to make my own with a few tweaks.
The first important feature is that this module calls one or more observer methods when the observed object's state is changed. When you add an observer, you also have to specify the method that will be called (by using a symbol). You can add the same observer again specifying yet another method (so if you add an observer twice (two different methods), when the object's state changes, both methods will be called).
Ruby's Observable module seems to call the #update
method on the observer. I prefer to choose the method to be called, so I did that change.
The freedom to associate multiple methods to the same observer (so it is called multiple times per state change) is something I'm unsure if it is useful in any way, though. What do you think about that?
The second important feature is the ability to choose which instance variables (using symbols) will be passed to the observer when it is notified of a state change. This way, when the observer is notified, it won't have to manually read the object's instance variables, since such variables will be passed as arguments to its method.
module Observable
def add_observer(observer,method,*instance_variables)
@observers ||= {}
@observers[observer] ||= []
entry = [method,instance_variables]
@observers[observer] << entry unless @observers[observer].include?(entry)
end
def remove_observer(observer)
return unless @observers
@observers.delete(observer)
end
def state_changed
return unless @observers
@observers.each do |observer,entries|
entries.each do |entry|
variables = []
entry[1].each do |symbol|
variables << instance_variable_get("@#{symbol}")
end
observer.send(entry[0],*variables)
end
end
end
def count_observers
return @observers.size
end
alias_method :changed , :state_changed
end
Example:
observableObject.add_observer(self,:somethingChanged,:instanceVar1,:instanceVar2)
When observableObject
's state changes, self
's method #somethingChanged
will be called. And two instance variables from observableObject
(instanceVar1
and instanceVar2
) will be passed to the method.
What do you think of this implementation? I like the fact that it seems to be more flexible (being able to choose which method to be called and, optionally, what instance variables to pass).