Did You Hear Something? Observer Pattern vs. Event Listeners

The Observer Pattern is like a DMV wait line. Event Listeners are more like a fire truck with its sirens blaring. Let me explain, and give you an example of each — the former in Ruby, and the latter in JavaScript.

Many people introduced to Observer Pattern will find that it is very similar to Event Listeners. Both have objects, “observers” and “listeners”, that are waiting for something to notify them before they can do their thing.

However, while some use cases of Event Listeners may follow the Observer Pattern, not every implementation of Event Listeners fits in the Observer Pattern. A general difference between the two is that observers are watching something specific, while listeners are not.

More specifically:

Observers are registered to the subjects they are observing, and a subject knows all the observers it notifies. The subject explicitly notifies each of its observers when there is an event.

Listeners, on the other hand, are listening for events on a global Events instance. They are not paying attention to any one subject, but instead are listening for a global Events broadcast that an event has happened. Any objects that are triggering events will broadcast their events without knowing who they are broadcasting to.

Let’s look at some examples!

Observer Pattern

DMV waiting area with people and one skeleton waiting - Now serving number 2

The Observer Pattern is like a DMV wait line. You show up at the DMV and register with them for a wait number. The DMV is the subject, when you register to get your wait number the DMV adds you to its list of observers. Everyone waiting at the DMV is an observer and is notified when a new wait number is called to the window.

Here’s the scenario in (ruby) code. We have our Subject and Observer classes:

# Subject
class DMV
	def initialize
    @observers = []
  end

	def add(observer)
    @observers << observer
  end

  def remove(observer)
    @observer.delete(observer)
  end

  def notify
    @observers.each do |observer|
			observer.update
    end
  end
end

#Observer
class Driver
  attr_reader :name

  def initialize(name)
		@name = name
  end

  def update
    puts "#{name} has been alerted"
  end
end

You can register instances of a Driver to an instance of a DMV :

oakland_dmv = DMV.new

freddie = Driver.new("Freddie")
brian = Driver.new("Brian")

oakland_dmv.add(freddie)
oakland_dmv.add(brian)

berkeley_dmv = DMV.new

roger = Driver.new("Roger")
john = Driver.new("John")

berkeley_dmv.add(roger)
berkeley_dmv.add(john)

And now whenever an instance of DMV has a state change, you can call notify() which will call update() on all the observers.

oakland_dmv.notify()
> "Freddie has been alerted"
> "Brian as been alerted"

berkeley_dmv.notify()
> "Roger has been alerted"
> "John has been alerted"

As you can see, each instance of a DMV only notifies observers that were registered to them.

You can pass data from the Subject to the Observers via notify() and update() . To learn more about the different ways to pass data with the Observer Pattern, checkout Intro to Observer Pattern.

Event Listeners

fire engine coming down the road with two cars getting out of the way

A common form of Event Listeners we see are JavaScript’s event listeners, which are more like a fire truck with its sirens blaring. The fire truck doesn’t know who is listening, but will sound its sirens to broadcast to anyone who is listening that this event is happening. People who are driving along the road (ostensibly) know how to respond when they hear sirens, but they aren’t specifically waiting for a siren to sound off as they are commuting to work.

Again, let’s take a look at a code example, this time in JavaScript:

class FireTruck {
  turnOnSirens() {
    const sirensBlaring = new Event("sirensBlaring");
		document.dispatchEvent(sirensBlaring);
  }
}

class Driver {
  constructor() {
    document.addEventListener("sirensBlaring", this.pullOver);
  }

  pullOver() {
		console.log("safely pull over");
  }
}

As you can see in the example above, the FireTruck doesn’t need to keep track of who is listening for its event. In fact, there could be multiple instances of FireTruck and every instance of Driver would be able to respond to "sirensBlaring" . On the other hand, in the Observer Pattern example above, you can have multiple instances of DMV and they would each have their own list of Observers.

One thought on “Did You Hear Something? Observer Pattern vs. Event Listeners

Leave a Reply