Today, we’ll look at one of the most useful patterns - The Observer.
This is what the GoF have to say about the Observer:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
We shall use the UML diagram to help us understand the pattern:
(Credits: http://www.wikipedia.com/)
The Subject
We begin with the Subject. This is the object that we are interested in when it’s state changes.
Subject has an observerCollection
field. As it’s name suggests, this is typically a list collection (Array, List, etc). This stores a collection of Observers which we will take a look next.
The Observer
The parent Observer defines one method - notify()
. Classes which inherit the Observer (ConcreteObserverA
, ConcreteObserverB
) are expected to implement notify()
.
PUB/SUB
This pattern is also known as the Publisher/Subscriber, or PUB/SUB for short.
Let’s find out why:
Subscribing and Unsubscribing
If the Subject
needs to inform certain Observer
s, then it calls the registerObserver(observer)
. Similarly, once it can choose to remove any Observer
by calling unregisterObserver(observer)
.
Publishing
Here’s where the fun starts. Let’s see some code that implements the UML diagram above:
class Subject
def initialize
@observers = []
end
def notify_observers
@observers.each do |observer|
observer.notify
end
end
def register_observer(observer)
@observers << observer
end
def unregister_observer(observer)
@observers.delete(observer)
end
end
Then the Observer:
class ObserverOne
def notify
puts "Observer 1 called."
end
end
class ObserverTwo
def notify
puts "Observer 2 called."
end
end
Then we add our observers:
subject = Subject.new
subject.register_observer(ObserverOne.new)
subject.register_observer(ObserverTwo.new)
Now, whenever Subject
‘s state changes, it just has to call notify_observers
:
class Subject
# …
def change_variable
# …
notify_observers
end
end
Key Takeaways
The Observer pattern great for reducing the coupling between different components when these components need to be informed about changes.
By separating the Subject
and the Observer
, we have a clean separation of concerns.
Examples of Observer in use
Ruby has is very own Observable
module, so there’s really no need to implement one your own. See the documentation. Notice that the methods implemented are pretty similar.
Rails makes use of observers heavily. Here’s a typical example:
class User < ActiveRecord::Base
after_create :send_email
def send_email
#send a welcome email
end
end
Thanks for reading!
References
Olsen, R. (2008) Design patterns in Ruby. Upper Saddle River, NJ: Addison-Wesley, p.95-110.
Gamma, E. (1995) Design patterns. Reading, Mass.: Addison-Wesley, p.293-303.