0 XP · 0 scenes

Observer

Tell everyone who is interested when something changes
The problem

After uploading a video the channel code calls the email sender, the mobile push service and the analytics tracker by name.

The idea

The publisher keeps a list of subscribers that all share a tiny interface, update().

Reach for it when

One object changes and many others must react

1

The picture from life

You subscribe to a YouTube channel. When the creator uploads, every subscriber gets a notification. The creator does not know or care who they are, and you can unsubscribe at any time without the creator changing anything.

2

The problem

What goes wrong when you do not use it.

After uploading a video the channel code calls the email sender, the mobile push service and the analytics tracker by name. Adding a fourth listener means editing the upload code again, and the channel is tied to every listener.

✗ Before
Channelupload(video): email.send(video) app.push(video) analytics.log(video)EmailPushAnalytics
  • calls / uses
The channel knows every listener by name and calls each one. A new listener means editing the channel.
Reach for it when
  • One object changes and many others must react
  • The set of listeners changes at run time
  • The publisher must not depend on its listeners
3

The idea

How the pattern fixes it.

The publisher keeps a list of subscribers that all share a tiny interface, update(). To announce, it loops through the list. Anyone can subscribe or unsubscribe.

✓ After
Channelsubscriberssubscribe(s)unsubscribe(s)upload(video)«interface»Subscriberupdate(video)ViewerAnalyticsnotifies all
  • implements
  • calls / uses
Listeners subscribe themselves. The channel only knows the Subscriber interface and notifies all.

Who is who

Channel (subject)
Holds subscribers; subscribe(), unsubscribe(), upload().
Subscriber (observer)
Interface with update(video).
Viewer, Analytics...
Concrete observers reacting in their own way.

Build it in steps

  1. 1Define the observer interface.
  2. 2Subject keeps a list and offers subscribe / unsubscribe.
  3. 3On change, loop and call update().
  4. 4Observers register themselves.
4

Watch it run

Step through the calls. Tap an arrow to jump to it.

ChannelAshaBala1subscribe(asha)2subscribe(bala)3upload('Intro')4update('Intro')5update('Intro')6unsubscribe(bala)7update('Part 2')
Step 1/7

Asha subscribes to the channel.

subscribe(asha)
5

The code

Python and Java. Try writing the classes yourself from the diagram first.

class Channel:                                 # the subject
    def __init__(self):
        self.subscribers = []

    def subscribe(self, subscriber):
        self.subscribers.append(subscriber)

    def unsubscribe(self, subscriber):
        self.subscribers.remove(subscriber)

    def upload(self, video):
        for subscriber in list(self.subscribers):
            subscriber.update(video)               # tell everyone


class Viewer:                                      # an observer
    def __init__(self, name):
        self.name = name
        self.inbox = []

    def update(self, video):
        self.inbox.append(video)


def demo():
    channel, asha, bala = Channel(), Viewer("Asha"), Viewer("Bala")
    channel.subscribe(asha)
    channel.subscribe(bala)
    channel.upload("V1")
    channel.unsubscribe(bala)
    channel.upload("V2")
    return asha.inbox, bala.inbox

What you gain

  • Loose coupling: subject knows only the interface
  • Add or remove listeners at run time

What it costs

  • Updates arrive in no guaranteed order
  • Forgotten unsubscribes leak memory and cause surprise calls

You have already met it in

  • Event listeners in the browser (addEventListener)
  • Pub/sub systems, Kafka topics, RxJS and Java's PropertyChangeListener
  • React state subscriptions

Often mixed up with

  • MediatorObserver is a one-way broadcast; Mediator coordinates two-way talk between many objects.
  • Chain of ResponsibilityObserver tells all listeners; a chain stops at the first handler that deals with it.
6

Make it stick

Build a StockTicker that notifies a PriceAlert (threshold) and a Logger. Unsubscribe the alert after it fires once.

Confidence