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:
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 parent Observer defines one method -
notify(). Classes which inherit the Observer (
ConcreteObserverB) are expected to implement
This pattern is also known as the Publisher/Subscriber, or PUB/SUB for short.
Let’s find out why:
Subscribing and Unsubscribing
Subject needs to inform certain
Observers, then it calls the
registerObserver(observer). Similarly, once it can choose to remove any
Observer by calling
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)
Subject’s state changes, it just has to call
class Subject # … def change_variable # … notify_observers end end
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
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!
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.