Hi,
I am reading Design Patterns in Ruby, and was looking at the code of the
observer module. On line 184, in notify_observers, there is a loop on
all
registered observers:
for i in @observer_peers.dup
i.update(*arg)
end
Why is there a “dup” on the array? Is that really necessary? Isn’t this
a
waste of memory? I am sure there is a really good explanation, but I
don’t
grasp it.
I also have another question: why does the subject (the notifying class)
need to call “changed”? Wouldn’t it be sufficient to call
notify_observers?
I mean, if I call notify_observers in the Subject class, doesn’t that
imply
has something has changed?
Why is there a “dup” on the array? Is that really necessary? Isn’t
this a
waste of memory? I am sure there is a really good explanation, but I
don’t
grasp it.
I’m totally guessing here, but could it be to keep the list from
changing while it iterates?
I’m totally guessing here, but could it be to keep the list from
changing while it iterates?
How could that ever happen?
def notify_observers(*arg)
if defined? @observer_state and @observer_state
if defined? @observer_peers
for i in @observer_peers.dup
i.update(*arg)
end
end @observer_state = false
end
end
@observer_peers will contain objects that implement the update method.
I also have another question: why does the subject (the notifying class)
need to call “changed”? Wouldn’t it be sufficient to call notify_observers?
I mean, if I call notify_observers in the Subject class, doesn’t that imply
has something has changed?
Consider the case:
def do_stuff
step_that_might_change_self()
another_step_that_might_change_self()
yet_another_step_that_might_change_self()
end
Any of the methods called by do_stuff MIGHT change the data, but then
again they might not. do_stuff should appear as an atomic operation
from outside the object, so we don’t want to call notify_observers in
all three methods. What we really want to do is do all of the steps
and then, when they are finished, notify our observers - but only if
we’ve actually been changed. So we write it like this:
def do_stuff
step_that_might_change_self()
another_step_that_might_change_self()
yet_another_step_that_might_change_self()
notify_observers
end
And then it is each step’s responsibility to call #changed if and only
if they actually made a change. If a change was made by one or more
steps, our observers are notified ONCE at the end.
And then it is each step’s responsibility to call #changed if and only
if they actually made a change. Â If a change was made by one or more
steps, our observers are notified ONCE at the end.
Yes, in this case it makes sense, but think of this:
def do_stuff @mint = ‘blue’
notify_observers
end
Nice and clean, isn’t it?
If I implement something like you sad, wouldn’t it make more sense to
create
a @changed variable in the Subject class, and call notify_observers only
if @changed == true instead of forcing a call to changed every time?
Well, it’s perfectly fine to me how it is implemented now, it just looks
a
bit ugly to me, but maybe it’s just me (that call to changed does not
really add anything, and the functionality it provides is trivial (if it
is
intended like you explained it)).
Why is there a “dup” on the array? Is that really necessary? Isn’t
this a
waste of memory? I am sure there is a really good explanation, but I
don’t
grasp it.
(waste of memory? one array? … who cares?)
what if one of the members of @observer_peers’ update method removes
everything from @observer_peers? How will the rest of the members get
their update? What if they needed to do stuff to properly clean up too?
what if one of the members of @observer_peers’ update method removes
everything from @observer_peers? How will the rest of the members get
their update? What if they needed to do stuff to properly clean up too?
what if one of the members of @observer_peers’ update method removes
everything from @observer_peers? How will the rest of the members
get their update? What if they needed to do stuff to properly clean
up too?
How would an observer peer have the ability to change the list (other
than removing itself, of course)? it seems to me that the list owner
would not allow that kind of access. On the other hand, perhaps
removing itself from the list might also hose the iteration.
Nice and clean, isn’t it?
If I implement something like you sad, wouldn’t it make more sense to create
a @changed variable in the Subject class, and call notify_observers only if @changed == true instead of forcing a call to changed every time?
What you describe is exactly what happens if you use #changed and #notify_observers the way they are intended. Look into the
implementation of #changed and #notify_observers.
And for simple cases nothing stops you from doing something like this:
def force_notify
changed
notify_observers
end
Well, it’s perfectly fine to me how it is implemented now, it just looks a
bit ugly to me, but maybe it’s just me (that call to changed does not
really add anything, and the functionality it provides is trivial (if it is
intended like you explained it)).
What’s wrong with having a method with trivial implementation? Note,
that the method has the added advantage to be overridable and changeable
so you are a lot more flexible.
Kind regards
robert
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.