Design Pattern: Observer and Podcasts

Design Pattern: Observer and Podcasts

Design patterns in life and Ruby — gain an intuitive understanding of OO design patterns by linking them with real-life examples.

 

If you listen to podcasts, you are already familiar with the Observer pattern. In fact, you are an “observer”.

Here’s the definition for the Observer pattern:

The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

 

Let’s look at the definition as related to podcasts.

I find an interesting podcast named developer tea.

After clicking the SUBSCRIBE button, I'm now on their subscriber list.

 

When developer tea releases a new episode, the Podcasts app will notify me and other subscribers and automatically download the new episode for us.

That’s exactly the definition of the Observer pattern!

The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.

There is a one-to-many relationship between the developer tea podcast and subscribers. When developer tea chanes state, such as releasing a new episode, all of developer tea's subscribers are notified and updated automatically.

 

Let’s implement it in Ruby.

Start with a simple version.

class Podcast
  attr_reader :episodes
  
  def initialize()
    @episodes = []
  end
  
  def add_episode(new_episode)
    episodes << new_episode
  end
end

The Podcast class holds a list of episodes and has a method to add_episode to the list.

Then we can create the developer_tea podcast and add episode #1 to it like this:

 

I want to get a notification whenever a new episode is released.

We can simply update me after adding a new episode to the list:

class Podcast
  attr_reader :episodes
  
  def initialize()
    @episodes = []
  end
  
  def add_episode(new_episode, sihui)
    episodes << new_episode
    sihui.update(self)
  end
end

And whenever I get an update from developer_tea, I can go ahead and download the latest episode.

I enjoy listening to developer_tea so much that I recommend it to my friend, Amber. Now, Amber wants to subscribe to it as well.

We need to make sure Amber also gets a notification whenever a new episode is released:

class Podcast
  attr_reader :episodes
  
  def initialize()
    @episodes = []
  end
  
  def add_episode(new_episode, sihui, amber)
    episodes << new_episode
    sihui.update(self)
    amber.update(self)
  end
end

Hmmm, now, the code does what we want.

But there is a problem.

Each time we want to add a subscriber, we have to redefine the class.

Is there a way to update the subscriber list dynamically without having to redefine the class?

 

We can keep a subscriber list!

 

class Podcast
  attr_reader :episodes, :subscribers
  
  def initialize()
    @episodes = []
    @subscribers = []
  end
  
  def add_subscriber(new_subscriber)
    subscribers << new_subscriber
  end
  
  def remove_subscriber(party_pooper)
    subscribers.delete(party_pooper)
  end
  
  def add_episode(new_episode)
    episodes << new_episode
    subscribers.each do |subscriber|
      subscriber.update(self)
    end
  end
end

The new Podcast class keeps a subscriber list with the help of two new methods: one for adding subscribers and one for removing subscribers. When an episode is released, we update each subscriber.

Unfortunately, Amber doesn’t enjoy the podcast as much as I do and decides to unsubscribe. We use the remove_subscriber method to remove her from the subscriber list.

Yay! You learn the Observer pattern!

 

A Design Principle Behind The Observer Pattern.

The Observer pattern utilizes the Loose Coupling design principle:

Strive for loosely coupled designs between objects that interact.

The Podcast class doesn’t know much about its subscribers besides the fact that each subscriber has an update method. This loose coupling minimizes the dependency between Podcast and its subscribers and maximizes flexibility. As long as it has an update method, a subscriber can be anything: a human, a group of people, an animal, or even a car.

 

Takeaways:

  1. The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
  2. Loose Coupling design principle: strive for loosely coupled designs between objects that interact.

Thanks for reading. Are there any other real-life examples of the Observer pattern you can think of?

Don't forget to subscribe. Next time we will talk about…

Enjoyed the article?

My best content on Software Design, Rails, and Career in Dev. Delivered weekly.

Unsubscribe at anytime. I'll never spam you. Powered by ConvertKit

2 Comments Design Pattern: Observer and Podcasts

  1. Sihui Huang

    Hi Bhanu, I’m glad you find it easy to understand. I found these examples just by thinking about the concept and try to draw analogies.

Leave A Comment

Your email address will not be published. Required fields are marked *