module Concurrent::Concern::Observable
The [observer pattern](en.wikipedia.org/wiki/Observer_pattern) is one of the most useful design patterns.
The workflow is very simple:
-
an `observer` can register itself to a `subject` via a callback
-
many `observers` can be registered to the same `subject`
-
the `subject` notifies all registered observers when its status changes
-
an `observer` can deregister itself when is no more interested to receive
event notifications
In a single threaded environment the whole pattern is very easy: the `subject` can use a simple data structure to manage all its subscribed `observer`s and every `observer` can react directly to every event without caring about synchronization.
In a multi threaded environment things are more complex. The `subject` must synchronize the access to its data structure and to do so currently we're using two specialized ObserverSet: {Concurrent::Concern::CopyOnWriteObserverSet} and {Concurrent::Concern::CopyOnNotifyObserverSet}.
When implementing and `observer` there's a very important rule to remember: **there are no guarantees about the thread that will execute the callback**
Let's take this example “` class Observer
def initialize @count = 0 end def update @count += 1 end
end
obs = Observer.new [obj1, obj2, obj3, obj4].each { |o| o.add_observer(obs) } # execute [obj1, obj2, obj3, obj4] “`
`obs` is wrong because the variable `@count` can be accessed by different threads at the same time, so it should be synchronized (using either a Mutex or an AtomicFixum)
Attributes
Public Instance Methods
@!macro observable_add_observer
Adds an observer to this set. If a block is passed, the observer will be created by this method and no other params should be passed. @param [Object] observer the observer to add @param [Symbol] func the function to call on the observer during notification. Default is :update @return [Object] the added observer
# File lib/concurrent-ruby/concurrent/concern/observable.rb, line 61 def add_observer(observer = nil, func = :update, &block) observers.add_observer(observer, func, &block) end
@!macro observable_count_observers
Return the number of observers associated with this object. @return [Integer] the observers count
# File lib/concurrent-ruby/concurrent/concern/observable.rb, line 101 def count_observers observers.count_observers end
@!macro observable_delete_observer
Remove `observer` as an observer on this object so that it will no longer receive notifications. @param [Object] observer the observer to remove @return [Object] the deleted observer
# File lib/concurrent-ruby/concurrent/concern/observable.rb, line 82 def delete_observer(observer) observers.delete_observer(observer) end
@!macro observable_delete_observers
Remove all observers associated with this object. @return [Observable] self
# File lib/concurrent-ruby/concurrent/concern/observable.rb, line 91 def delete_observers observers.delete_observers self end
As `#add_observer` but can be used for chaining.
@param [Object] observer the observer to add @param [Symbol] func the function to call on the observer during notification. @return [Observable] self
# File lib/concurrent-ruby/concurrent/concern/observable.rb, line 70 def with_observer(observer = nil, func = :update, &block) add_observer(observer, func, &block) self end