Implementing the Observer Pattern in Ruby

Introduction to the Observer Pattern in Ruby

Welcome back! We're continuing our exploration of Behavioral Patterns, now using Ruby. In this lesson, we delve into the Observer Pattern, an integral design pattern emphasizing communication between objects and distributing responsibilities effectively. In this pattern, an object, referred to as the subject, keeps track of its dependents, called observers, and automatically notifies them of any state changes.

Previously, we explored how to implement command-like behavior in Ruby. Building on that foundation, we will now examine how the Observer Pattern supports seamless and efficient communication between objects within Ruby's dynamic and expressive environment.

What You'll Learn

In this lesson, you will learn how to implement the Observer Pattern by understanding its main components and their roles in Ruby. We'll break down the pattern into digestible parts and showcase its practical application through straightforward examples.

Here's a simple illustration to get you started:

We begin by defining a NewsPublisher class that manages a list of subscribed observers. When new news is published, the NewsPublisher automatically notifies all subscribers by invoking their update method.

class NewsPublisher
  def initialize
    @subscribers = []
  end

  def add_subscriber(subscriber)
    @subscribers << subscriber
  end

  def remove_subscriber(subscriber)
    @subscribers.delete(subscriber)
  end

  def publish(news)
    @subscribers.each { |subscriber| subscriber.update(news) }
  end
end

Now, let's define a Subscriber module and a concrete implementation ConcreteSubscriber that prints the received news to the console.

module Subscriber
  def update(news)
    raise NotImplementedError, "Subclasses must implement `update`"
  end
end

class ConcreteSubscriber
  include Subscriber

  def initialize(name)
    @name = name
  end

  def update(news)
    puts "#{@name} received news: #{news}"
  end
end

Finally, we demonstrate the Observer Pattern in action by creating a NewsPublisher, adding subscribers, publishing news, and removing a subscriber.

news_publisher = NewsPublisher.new
subscriber1 = ConcreteSubscriber.new("Subscriber 1")
subscriber2 = ConcreteSubscriber.new("Subscriber 2")

news_publisher.add_subscriber(subscriber1)
news_publisher.add_subscriber(subscriber2)

news_publisher.publish("Breaking News 1")
news_publisher.remove_subscriber(subscriber1)
news_publisher.publish("Breaking News 2")

Let's understand the key components of the Observer Pattern in this example:

  • Subject (NewsPublisher): Maintains a list of observers and notifies them of any state changes. The NewsPublisher class holds a list of Subscriber objects and notifies them when new news is published.
  • Observer (Subscriber): Defines an interface for receiving updates from the subject. The Subscriber module specifies that the update method must be implemented.
  • Concrete Observer (ConcreteSubscriber): Implements the update method to receive and manage updates from the subject. The ConcreteSubscriber class prints the received news to the console.
  • Client: Demonstrates how to create a NewsPublisher, add subscribers, publish news, and remove subscribers using Ruby's syntax.
Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal