Don't like this style? Click here to change it! blue.css

Class 16: The Observer Pattern

The official version of the observer pattern is that one object is the subject of attention. Other objects can choose to be observers of the subject. When the subject has a state change it can notify all of the observers of the state change.

To pull this off the subject needs an array of observers and the observers need some sort of update function. When the subject is going to broadcast it will call update on each of the observers.

In this snippet the sun acts as the subject and the sky is its only observer:

See the Pen VeBZrZ by Andy Novocin (@AndyNovo) on CodePen.

Go forth and populate the Earth: Add an earth class and maybe some animals that are nocturnal and some animals that are diurnal. Give each an update. Simulate nature.

You could of course model interesting behaviors like crickets listening to each other at night and trying to find each other. Once you start modeling reality you've got plenty of room to roam.

Introduce death: Now write a remove function which takes an observer out of the sun's observers array. Punish the diurnal creatures for their arrogance and give them a finite life span, display the number of days they have left to live. (Let's see how they handle their own mortality.) When they die remove them from the daily grind. If you are feeling very cheeky you can add click listeners that let you interfere in their world.

Last time I never showed you my pushState example. Remind me to do so now.

Publish/Subscribe maybe Mediator

You will often see Observer and Pub/Sub listed as the same pattern while other writers will distinguish the two. I want to show you a variant which should feel useful and vaguely familiar. That is, letting observers subscribe to specified channels and set their callbacks.

You could probably even call this a mediator pattern when used in a specific way (one object making sure that the correct message gets to the correct listener). I'm not one for dogmatic debates about the classification of patterns. The point is that it's a useful setup for apps. You've been using it already having 'click' listeners all the time.

The distinctions between the patterns are usually how the idea is used (observer implies listening to the state of the subject while pub/sub is a bit more of a media outlet passing news along). My preference for loosely specified phrasing is because I've largely developed alone in my career. In a team, having a clear and well-understood vocabulary lets you communicate your architectures quickly and effectively. So whenever I join a project I spend the first stage clarifying the common syntax of my teammates.

OK so here is my silly example demonstrating pub/sub for vanilla classes (ES5 style). One object is counting numbers while an audience of number fans get excited whenever they hear multiples of their favorite primes!

See the Pen Channels with Callbacks by Andy Novocin (@AndyNovo) on CodePen.

Spread the love OK, so I want you to now have number fans inherit from EventHub so that other objects can listen to those folks. Now build numberFanLovers that listen to their significant others and become happy when their objects of affection are happy. (Make one poly-amorous numberlover that is happy when any number fan is happy. This person ends up loving almost all composites.)

Pros/Cons

When using this design paradigm in your code you have loose coupling between your objects. You can have objects create emergent complexity without a complex codebase. If you don't keep a good diagram/plan/specification of the chain of communication you might end up with "event-hell" where things are happening and you aren't sure why. So it's important to keep a clear heirarchy of listeners/targets.

Built-in Custom Events

I wanted to start with a DIY vanilla JS pub/sub, but there are several ways of using native browser support to send events around but they always involve the DOM or the window.

I've used https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage for fun and profit by making pages that spawn remote interfaces and communicate via messaging like this. (Try making a page where you click a button to spawn a new window then use ASDW to move that window around your screen.)

Another built-in custom event engine comes with every DOM element. You can use $el.addEventListener to listen for any event name you want. To trigger that custom event you'll need to create a new Event with the appropriate name then use dispatchEvent to send it out there.

If there is time task: Simplify the numberFan sample to have the DOM elements for each listening class be the hub (this is no longer very MVC by the way).